2017-07-01 16:45 230人阅读 评论(0) 收藏 举报
分类:
Android(47)
目录(?)[+]
做Android开发的少不了对触摸、按键事件进行处理,对于手机来说,主要是手势移动、触摸按下等,而TV主要通过遥控器、按键操作,按键事件不同于触摸事件,必须先获得焦点,然后才能移动、选择。
android输入设备支持鼠标、键盘(按键)、触摸屏(单点、多点)、轨迹球等,这些设备所产生的输入事件Input Event从底层驱动开始经过input子系统核心层到达Event
Handler事件层,最终把事件copy_to_user到用户空间,然后由用户空间层获取这些事件进行分发、传递。整个过程涉及到内核层、Framework层以及应用层,内核层传递过程不在本文研究范围内,本文主要对按键事件在Framework层、应用层的传递过程进行分析(本文基于Android5.1.1版本),带着问题出发:
1. Framework层如何获得输入事件
2. Framework层获得按键事件后如何处理、存储
3. Framework层如何分发、传递给应用层
4. Framework层服务端管道和应用程序客户端管道如何创建、注册
5. 应用层如何从Framework层接收按键事件
6. 应用层接收到按键事件后如何传递
7. 特殊按键如何处理
8. 总结
1. Framework层如何获得输入事件
要分析输入系统,最好先从输入事件系统服务InputManagerService入手,这是了解输入系统的起点,所有其他相关类、线程都因此被创建或间接创建。
1.1 InputManagerService的初始化
Android系统启动时,android部分第一个用户空间进程zygote(注:如果从Linux角度出发,第一个用户空间进程是init)首先fork创建了SystemServer对象,随后SystemServer创建了核心服务ActivityManagerService、PowerManagerService、PackageManagerService、InputManagerService等,相关代码在SystemServer.Java的run方法中,与InputManagerService相关部分:
1) inputManager = new InputManagerService(context);
2) wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
3) ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
4) inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
5) inputManager.start();
1.1.1 InputManagerService的构造方法
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
创建了一个InputManagerHandler对象,参数是HandlerThread中创建的looper对象
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
用Looper中的消息队列作为参数,调用本地方法nativeInit,返回C++中的NativeInputManager对象地址赋给mPtr,mPtr在1.5节会用到。
LocalServices.addService(InputManagerInternal.class, new LocalService());
把InputManagerInternal.class和LocalService对象作为一对映射添加到ArrayMap<Class<?>, Object>中
1.1.2 nativeInit方法实现
static jlongnativeInit(JNIEnv* env, jclassclazz,
jobjectserviceObj, jobjectcontextObj, jobjectmessageQueueObj) {
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);
}
android_os_MessageQueue_getMessageQueue方法:
sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobjectmessageQueueObj) {
jlongptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr);
return reinterpret_cast<NativeMessageQueue*>(ptr);
}
获得了C++层NativeMessageQueue对象,NativeMessageQueue对象是在创建Looper对象时创建的,在本博客Handler机制中已经分析过
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
创建了NativeInputManager对象,返回到Java层的nativeInit,并将地址赋给mPtr;getLooper()获得c++层的Looper对象,在Handler机制中,此时Looper对象也已初始化,同时创建了管道并注册在epoll兴趣列表中
NativeInputManager的构造函数:
NativeInputManager::NativeInputManager(jobjectcontextObj,
jobjectserviceObj, 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);
}
把获得的Looper对象传给过来赋给mLooper,用来回调Looper对象的方法;创建c++层中全局变量mContextObj, mServiceObj;创建EventHub对象并作为参数创建InputManager对象。
1.1.3 EventHub.cpp的构造函数
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);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
mINotifyFd = inotify_init();
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d",
DEVICE_PATH, errno);
struct epoll_eventeventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
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.u32 = EPOLL_ID_WAKE;
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);
}
初始化必要的变量,采用epoll机制系统调用接口epoll_create创建epoll对象,返回文件描述符mEpollFd,代表epoll对象;采用inotify机制监听文件或目录的移动、读取、写入或删除等事件,inotify机制主要包含2个系统调用接口:inotify_init, inotify_add_watch
inotify_init:创建一个inotify对象,如果成功,返回一个文件描述符,作为该对象;返回-1表示出错
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE)
inotify_add_watch:把监控项添加到mINotifyFd对象的监控列表中,第二个参数DEVICE_PATH就是被监控对象,该对象一般是文件或目录,本文中被监控的DEVICE_PATH就是/dev/input目录;第三个参数是一个位掩码,表示被监控对象上发生的具体事件,可以由1个或多个掩码位或门组成。IN_DELETE:当被监控目录内删除文件或目录时触发该事件;IN_CREATE:当被监控目录内创建文件或目录时触发该事件。比如,插入、拔出鼠标时,就会触发该事件。
如果inotify_add_watch执行成功,返回一个非负监控描述符(假如为wd),代表被监控的项,如果将来不需要再监听了,可以使用inotify_rm_watch(fd, wd)删除所添加的监控项wd。
struct epoll_eventeventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
把inotify对象mINotifyFd添加到epoll对象的兴趣列表中,此处采用inotify与epoll机制结合起来检查文件
eventItem.data.u32 = EPOLL_ID_WAKE;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
创建了管道对象读取端文件描述符mWakeReadPipeFd并添加到epoll对象的兴趣列表中
读到此处,提出2个问题:
Q1 epoll机制一般有3个系统调用接口,而截止到此处,只提到epoll_create, epoll_ctl,还缺epoll_wait,猜测在代码某处肯定有epoll_wait,否则epoll机制无法工作
Q2 如果找到了epoll_wait,调用进程处于等待状态,那么肯定还有一处用来唤醒调用进程的代码,比如Looper的wake函数或者其他地方调用了write系统调用
记住这两个问题,有助于在分析多进程控制时的代码走向
1.1.4 InputManager.cpp的构造器
mInputManager = new InputManager(eventHub, this, this);
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();
}
第一个参数是刚创建的EventHub对象,第二、三个参数都是this,当前NativeInputManager对象,传递过去后分别是InputReaderPolicyInterface、InputDispatcherPolicyInterface类型,这是为何?因为NativeInputManager继承了InputReaderPolicyInterface、InputDispatcherPolicyInterface类,实际类型还是NativeInputManager
用这两个传递过去的对象类型作为参数分别创建了InputDispatcher和InputReader对象,再调用initialize方法分别创建了与InputDispatcher和InputReader对应的线程InputDispatcherThread和InputReaderThread对象
1.1.5 InputDispatcher的构造函数
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
}
把传递过来的NativeInputManager对象赋给mPolicy,该NativeInputManager对象又是InputDispatcherPolicyInterface接口类型,然后又初始化了很多变量,其中包括:
mLooper = new Looper(false);
创建并初始化了Looper对象,在Looper构造方法创建了管道并采用epoll机制把管道加入到兴趣列表中。
注意,此处创建的Looper对象是在InputDispatcher中的,与主线程中的Looper没有关系。
Q3 既然有了epoll_ctl,那肯定某处会调用epoll_wait
1.1.6 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
}
第一个参数是EventHub对象,第二个policy赋值给mPolicy,policy是InputReaderPolicyInterface接口类型,实际是NativeInputManager对象类型。第三个listener实际是InputDispatcher类型,因为InputDispatcher实现了InputDispatcherInterface,InputDispatcherInterface又实现了InputListenerInterface,因此policy也是InputListenerInterface对象类型
mQueuedListener = new QueuedInputListener(listener);
把InputListenerInterface对象类型listener作为参数创建QueuedInputListener对象,传递过去后赋给mInnerListener变量
1.1.7 InputManager.cpp的initialize函数
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
用InputReader对象作为参数创建InputReaderThread线程对象,用InputDispatcher作为参数创建InputDispatcherThread线程对象,InputReaderThread的构造函数:
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
把InputReader对象赋给mReader变量
InputDispatcherThread的构造函数:
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
把InputDispatcher对象赋给mDispatcher变量
进程执行到此处,InputManagerService的初始化就完成,整个过程都是在创建、初始化各种对象。
Q4 既然创建了线程对象,那么就应该在某处启动线程,否则线程无法运行,在哪里启动线程
1.2 WindowManagerService的main方法
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
public static WindowManagerServicemain(final Contextcontext,
final InputManagerServiceim,
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);
}
}, 0);
return holder[0];
}
mInputManager = inputManager;
main方法创建了WindowManagerService对象,第二个参数是InputManagerService对象,传递到WindowManagerService的构造函数中赋给了mInputManager
1.3 ServiceManager的addService方法
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
把InputManagerService服务注册到ServiceManager中
1.4 InputManagerService的setWindowManagerCallbacks方法
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
把InputMonitor对象传递到InputManagerService中去,方便回调,比如7.2节通过该参数回调InputMonitor中的interceptKeyBeforeQueueing方法
1.5 InputManagerService的start方法
start方法中有两句:
nativeStart(mPtr);
Watchdog.getInstance().addMonitor(this);
nativeStart的本地实现:
static void nativeStart(JNIEnv* env, jclassclazz, jlongptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_tresult = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
ptr在1.1.1节已经提到过,是NativeInputManager对象地址,只不过是长整形,此处再转化成NativeInputManager型指针
Watchdog是看门狗,一个单例类,addMonitor方法把InputManagerService对象添加到Watchdog,便于回调
Q5 创建了看门狗,有什么用?
nativeStart的传递过程: nativeStart —-> com_android_server_input_InputManagerService.cpp的nativeStart —-> InputManager.cpp的start()
1.5.1 InputManager.cpp的start
status_tInputManager::start() {
status_tresult = 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;
}
首先启动分发器线程InputDispatcherThread,调用run方法后,开始执行threadLoop方法,如果threadLoop返回true,就再次执行threadLoop方法直到requestExit方法停止线程;再调用InputReaderThread的run方法启动接收器线程。这回答了1.1.7节Q4问题,只要创建了线程,那就应该有启动线程的地方。
threadLoop中调用了mDispatcher->dispatchOnce()
1.5.2 InputDispatcher.cpp的dispatchOnce
void InputDispatcher::dispatchOnce() {
nsecs_tnextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex_l(mLock);
mDispatcherIsAliveCondition.broadcast();
// 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_tcurrentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
一开始,CommandQueue队列中没有任何命令,haveCommandsLocked为false,if语句成立,执行dispatchOnceInnerLocked
1.5.2.1 InputDispatcher.cpp的dispatchOnceInnerLocked
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
// Get ready to dispatch the event.
resetANRTimeoutsLocked();
}
mPendingEvent初始化为空,mInboundQueue队列也为空,下面语句:
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。