android4.3 按键消息处理分析

来源:互联网 发布:centos回到根目录 编辑:程序博客网 时间:2024/06/01 09:28

2014-05-14     我来说两句    来源:android4.3 按键消息处理分析  
收藏    我要投稿

Android4.3按键消息处理与之前的版本有稍微的区别,基本原理还是一样的,这里主要从两个阶段来分析:

1.前期的准备工作,即开机时启动相应的的线程,静候按键事件的来临

2.当有按键消息时,进行消息的分发等处理

先看一张类图:

\

从类图中看出,主要涉及到的类有PhoneWindowManager、WindowManagerService、inputManagerService、 InputManager

先看第一个问题,前期的准备工作:

1.开机时先启动inputManagerService,由ServerThread负责启动;

  inputManager = new InputManagerService(context, wmHandler);            Slog.i(TAG, "Window Manager");            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();

看inputManagerService的构造函数:

 public InputManagerService(Context context, Handler handler) {        this.mContext = context;        this.mHandler = new InputManagerHandler(handler.getLooper());        mUseDevInputEventForAudioJack =                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="                + mUseDevInputEventForAudioJack);        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());    }
先new一个InputManagerHandler,然后调用一个native方法,把service和handler的消息队列作为参数传入,

nativeInit对应是com_android_server_input_InputManagerService.cpp中的nativeInit,,这个通过JNI的机制进行关联。

这里不多说,看nativeInit:

static jint nativeInit(JNIEnv* env, jclass clazz,        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {    sp 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(im);}
这里主要是创建一个NativeInputManager对象,看起构造函数:

NativeInputManager::NativeInputManager(jobject contextObj,        jobject serviceObj, const sp& looper) :        mLooper(looper) {    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 = new EventHub();    mInputManager = new InputManager(eventHub, this, this);}
这里主要是创建一个InputManager,看起构造函数:

InputManager::InputManager(        const sp& eventHub,        const sp& readerPolicy,        const sp& dispatcherPolicy) {    mDispatcher = new InputDispatcher(dispatcherPolicy);    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);    initialize();}void InputManager::initialize() {    mReaderThread = new InputReaderThread(mReader);    mDispatcherThread = new InputDispatcherThread(mDispatcher);}

这里看到了创建对象InputDispatcher 、InputReader以及两个时刻在跑的线程对象:mReaderThread、mDispatcherThread

至此初始化的第一步是完成了,但创建的线程还没start,还开始正真的干活,看开启过程

\

至此前期的准备工作都做完,两线程开始干活,静候按键事件来临

2.当有按键事件时两个线程处理流程见下图:

\

两条主线:

a. InputReader从EventHub中获取到按键事件,并通知InputDispatcher;InputDispatcher接到通知后调用

interceptKeyBeforeQueueing方法进行相关的操作,并把按键事件加入到队列中,等待后面处理。

加入队列源码:

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {    bool needWake = mInboundQueue.isEmpty();    mInboundQueue.enqueueAtTail(entry);    traceInboundQueueLengthLocked();

b. InputDispatcher从消息队列中获取按键消息,调用interceptKeyBeforeDispatching方法判断是否对此消息进行拦截,

根据其结果进行判断:

    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,            &event, entry->policyFlags);    mLock.lock();    if (delay < 0) {        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;    } else if (!delay) {        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;    } else {        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;        entry->interceptKeyWakeupTime = now() + delay;    }


其中在InputDispatcher中调用的interceptKeyBeforeQueueing和interceptKeyBeforeDispatching方法都是对应着

PhoneWindowManager中的同名方法。

0 0
原创粉丝点击