以TouchEvent为主,看一下View和ViewGroup内部是如何处理Input Events的;
首先来看事件的产生来源:
一、获取事件:
事件的来源可以分为“软件”,“硬件”两种;
主要的事件包含有:
按键事件(KeyEvent) :即物理按键按下产生的事件,相关的常用物理按键一般有HOME,BACK等
触摸事件(TouchEvent):
鼠标事件(MouseEvent)、轨迹球事件(TrackBallEvent)(这两个已经不常见);
针对所有事件的共性抽象出了InputEvent接口;其有两个子类:KeyEvent,MotionEvent;
1、事件的投递流程:
1>源信息采集
对“硬件源”产生的原始信息进行收集;它需要Linux内核驱动的支持,Android系统通过/dev/input下的节点来访问当前发生的事件。
2>前期处理
对收集到信息进行筛选以及格式转化
3>WMS分配
WMS是窗口的Manager,同时也是InputEvent的派发者。
4>应用程序处理
WMS会先把事件传递到对应ViewRootImpl,ViewRootImpl分发事件,传递给相应的DecorView,DecorView在调用Activity中的Window.Callback将事件传递给Activity;然后Activity在通过dispatchTouchEvent分发事件,下面就来到熟悉的View事件分发机制;具体见《View机制深入学习(四)View的事件分发机制》
2、InputManagerService启动:
InputManagerService同样也是有SystemServer进程启动,这个在Android启动过程——init.rc,Zygote,SystemServer中已经提到过,
系统启动后创建init进程(pid=1),init进程创建出Zygote进程,然后Zygote进程孵化出SystemServer进程,在SystemServer进程中创建IMS:
/** @path: \frameworks\base\services\java\com\android\server\SystemServer.java */
class ServerThread extends Thread {
@Override
public void run() {
// 可以看到IMS和WMS是紧密相关的
......
// @value InputManagerService inputManager
inputManager = new InputManagerService(context, wmHandler);
Slog.i(TAG, "Window Manager");
// @value WindowManagerService wm
wm = WindowManagerService.main(context, power, display, inputManager,
uiHandler, wmHandler,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
ActivityManagerService.self().setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
.....
}
}
3、InputMangerService:
/** \frameworks\base\services\core\java\com\android\server\input\InputManagerService.java **/
public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
// 指向native端IMS类对象的地址
private final long mPtr;
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
// 创建native IMS对象
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
}
可以看到Java层的IMS实际上只是对Native层的InputManager的一层包装;其创建主要是native层进行创建,并把native层的InputManager地址赋值给InputManagerService的mPtr变量;
而且注意nativeInit中传入了Looper中的MessageQueue变量;
4、native层的InputManagerService——NativeInputManager类:
/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface
static jlong nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
// 创建一个Message Queue
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
// 可以看到NativeInputManager中包含有一个Looper,用以进行事件分派
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
// 返回创建的IMS实例对象的地址(强制转化为long类型)
return reinterpret_cast<jlong>(im);
}
可以看到首先通过android_os_MessageQueue_getMessageQueue函数获取到本地端的MessageQueue,这个在Handler机制中的本地解析《Handler机制深入解析》中已经提到,该NativeMessageQueue对象在java层创建Looper时创建实例,然后将地址指针赋值为Looper对应的MessageQueue中的ptr变量中,这里根据指针来获取该NativeMessageQueue对象;
根据NativeMessageQueue对象获取其中对应的Looper(native),用以创建NativeInputManger;来看NativeInputManager的构造函数:
5、NativeInputManager#NativeInputManager:
/** \frameworks\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;
}
// 创建EventHUb
sp<EventHub> eventHub = new EventHub();
// 创建InputManager实例
mInputManager = new InputManager(eventHub, this, this);
}
NativeInputManager中保存了Looper(native)实例;并且创建了EventHub,以及InputManager两个重要的对象;
EventHub从名字就可以看出,它是用来收集以及存储外部的输入事件的;
而InputManager则是对Event事件进行处理分发;
先来看EventHub:
(一)EventHub:
/*\frameworks\native\services\inputflinger\EventHub*/
static const char *DEVICE_PATH = "/dev/input";
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);
// 创建epoll对象
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
// 采用inotify机制监听文件或目录的移动、读取、写入或删除等事件
// 创建一个inotify对象
mINotifyFd = inotify_init();
// 把监控项添加到mINotifyFd对象的监控列表中
// 这里监听的文件路径为"/dev/input"
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
// 把inotify对象mINotifyFd添加到epoll对象的兴趣列表中,此处采用inotify与epoll机制结合起来检查文件
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
// 创建pipe
result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
// 设置为非阻塞
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
// 添加到epoll的兴趣列表中
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
int major, minor;
getLinuxRelease(&major, &minor);
// EPOLLWAKEUP was introduced in kernel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
在前面进行了一系列的变量的初始化;
然后epoll_create创建了一个epoll对象,可以看到和Handler中一样,IMS中也用到了epoll机制进行监听;
而后可以看到IMS是INotify机制和Epoll机制同时使用的:inotify_init创建iNotify对象,inotify_add_watch则将”/dev/input”路径添加到监听列表中;当”/dev/input”中文件发生变化,将会产生响应;
了解INotifiy文件系统监听机制:
《inotify – Linux 2.6 内核中的文件系统变化通知机制》
《Inotify: 高效、实时的Linux文件系统事件监控框架》
然后将iNotify对象添加到Epoll的兴趣列表中,进行监听;
然后同Handler机制,创建一个Pipe,然后设置为非阻塞形式,然后添加到epoll的兴趣列表中;下面就注意在何时调用epoll_wait来开启监听即可;这里仅进行了初始化;
(二)InputManager:
1)构造函数:
/** \frameworks\native\services\inputflinger\InputManager.cpp **/
class InputManagerInterface : public virtual RefBase {
private:
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
sp<InputDispatcherInterface> mDispatcher;
sp<InputDispatcherThread> mDispatcherThread;
// 构造函数
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
// 创建InputDispatcher
mDispatcher = new InputDispatcher(dispatcherPolicy);
// 创建InputReader
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
/*** 进行初始化 **/
void InputManager::initialize() {
// 创建两个Thread的实例
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
};
InputManager中传入了前面创建的EventHub对象;然后初始化了两个中重要的类,InputDispatcher,以及InputReader;
显然从名字可以看出 InputReader用来读取EventHub中的事件,然后通过InputDiapatcher进行分发(InputReader中持有InputDisptcher的引用);
先看InputDispatcher:
1.1)InputDispatcher:
继承关系:
class InputDispatcher : public InputDispatcherInterface
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface
构造函数:
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(