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> 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<jint>(im);
}
这里主要是创建一个NativeInputManager对象,看起构造函数:

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& 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> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}
这里主要是创建一个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();
}


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中的同名方法。

  

你可能感兴趣的:(Android4.3,按键消息处理)