InputManagerService的启动过程(一)

SystemServer 的main方法开始==》

SystemServer#
public static void main(String[] args) {
        new SystemServer().run();
    }

private void run() {
	//引导服务:ActivityManagerService、PowerManagerService、PackageManagerService等服务
       startBootstrapServices();
	//核心服务:teryService、UsageStatsService和WebViewUpdateService
       startCoreServices();
	//其他服务:eraService、AlarmManagerService、VrManagerService、InputManagerService等服务
       startOtherServices();
}

而InputManagerService的启动是在 startOtherServices中,startOtherServices方法还启动了其他的一些服务,这里只关注InputManagerService。

SystemServer#
private void startOtherServices() {
     WindowManagerService wm = null;
     InputManagerService inputManager = null;
     //创建InputManagerService实例
     inputManager = new InputManagerService(context);
     //内部会创建WindowManagerService实例,并且持有inputManager引用
     wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore, new PhoneWindowManager());
     ServiceManager.addService(Context.WINDOW_SERVICE, wm);
     //将InputManagerService实例添加到ServiceManager统一管理
     ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
    inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
    //启动InputManagerService
    inputManager.start();
}

WindowManagerService是输入系统的中转站,因此它必定持有了InputManagerService的引用。

InputManagerService的构建

public InputManagerService(Context context) {
       //拿到“android.display”线程的Looper创建一个InputManagerHandler
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
        //初始化InputManagerService
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    }

private static native long nativeInit(InputManagerService service,
         Context context, MessageQueue messageQueue);

继续跟进com_android_server_input_InputManagerService.cpp

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;
    }
    //可以看到创建了一个native层的NativeInputManager对象
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    //将native层的NativeInputManager对象的地址返回给java层
    return reinterpret_cast<jlong>(im);
}

NativeInputManager对象的构造

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    //创建EventHub用来监视设备节点
    sp<EventHub> eventHub = new EventHub();
    //构造一个InputManager对象
    mInputManager = new InputManager(eventHub, this, this);
}

输入事件比如触摸屏幕最终会被输入子系统采集,最终会传递给这些设备节点(/dev/input/…),在linux中一些皆文件,设备节点就是一个个文件,我们所有的输入事件信息都会被添加到这些设备节点里,而EventHub负责监视这些文件,EventHub是通过Epoll来实现的。而InputManagerService就是通过EventHub来获取这些原始输入事件的。

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    //用来将输入事件分发给合适的window
    mDispatcher = new InputDispatcher(dispatcherPolicy);
   //InputReader通过eventHub读取原始输入事件,并且持有InputDispatcher(用来分发事件)的引用
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

void InputManager::initialize() {
    //InputDispatcher和InputReader的执行都比较耗时,放到单独的线程中执行。
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

到这里InputManagerService的创建就结束了,接下来分析它的启动方法

SystemServer#
private void startOtherServices() {
     WindowManagerService wm = null;
     InputManagerService inputManager = null;
     //...
     //启动InputManagerService
    inputManager.start();
}
SystemServer#
public void start() {
     //直接调用了native层的启动方法,把native层NativeInputManager对象的指针传过去。
     nativeStart(mPtr);
}

继续往下查看com_android_server_input_InputManagerService.cpp

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    //获取NativeInputManager对象的指针
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    //启动
    status_t result = im->getInputManager()->start();
}

然后调用了InputManager的start方法,回顾下InputManager的创建

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

继续跟踪InputManager.cpp的start方法

InputManager.cpp#
status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    return OK;
}

直接调用了mDispatcherThread和mReaderThread这两个线程的run方法,这两个线程的创建前面已经提过。

先来分析下InputReaderThread这个类,它的实现位于InputReader.h

/* Reads raw events from the event hub and processes them, endlessly. */
/* 从event hub 中不停的读取原始事件,然后处理它们 */
InputReader.h#
class InputReaderThread : public Thread {
public:
    explicit InputReaderThread(const sp<InputReaderInterface>& reader);
    virtual ~InputReaderThread();

private:
    sp<InputReaderInterface> mReader;

    virtual bool threadLoop();
};

回顾下前面的分析,InputReaderThread持有InputReader,InputReader持有EventHub和InputDispatcher,这样在InputReaderThread线程中就可以不停的通过EventHub获取原始的输入事件,然后交由InputDispatcher处理了。这里有个虚方法threadLoop啥意思呢?源码中调用的是run方法和threadLoop有什么关系呢?

找到InputReaderThread的父类Thread的头文件

namespace android {
	class Thread : virtual public RefBase
	{
		public:
        // Start the thread in threadLoop() which needs to be implemented.
   		virtual status_t    run(    const char* name,
                                int32_t priority = PRIORITY_DEFAULT,
                                size_t stack = 0);
        private:
        // 1) loop: if threadLoop() returns true, it will be called again if
     	// requestExit() wasn't called.
   		// 2) once: if threadLoop() returns false, the thread will exit upon return.
        virtual bool        threadLoop() = 0;
    }
}

注释可以说很贴心了,调用run方法,最终会启动threadLoop,如果threadLoop返回true会被循环执行,如果返回false,只会被执行一次。ok跑题了,继续分析InputReaderThread的实现。

InputReader.cpp#
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
        Thread(/*canCallJava*/ true), mReader(reader) {
}

InputReaderThread::~InputReaderThread() {
}

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}

调用run会导致调用threadLoop方法,并且由于threadLoop返回true,threadLoop会被循环调用。在threadLoop内部又调用了mReader的loopOnce方法,而mReader就是InputReader继续跟进==》

InputReader.cpp#
//InputReader构造方法
//可以看到在初始化列表中将eventHub给到成员mEventHub,用QueuedInputListener来包装InputDispatcher
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener):mEventHub(eventHub)...{
    mQueuedListener = new QueuedInputListener(listener);
}

void InputReader::loopOnce() {
    //通过mEventHub的getEvents方法获取设备节点所有的事件信息保存到mEventBuffer中
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { 
        //如果有事件就对其进行加工处理。
        if (count) {
            processEventsLocked(mEventBuffer, count);
        }
        
    mQueuedListener->flush();
}
    
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    //遍历所有的事件
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            //这条分支用来处理输入事件
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            //这条分支用来处理设备事件,我们不关注
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

事件分为设备事件和原始的输入事件,我们这里只关注输入事件。

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    InputDevice* device = mDevices.valueAt(deviceIndex);
    device->process(rawEvents, count);
}

根据代码的语义,首先通过deviceId从mDevices获取到deviceIndex,然后再根据deviceIndex获取具体的输入设备,再调用InputDevice的process去处理具体的输入事件。

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
  
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
            } 
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                //调用InputMapper去处理事件
                mapper->process(rawEvent);
            }
        }
    }
}

遍历所有的原始事件,然后将这些事件交给每一个InputMapper去处理。InputMapper的实现类有很多,JoystickInputMapper(用于处理游戏手柄输入事件)、MultiTouchInputMapper(用于处理多点触摸输入事件)、KeyboardInputMapper( 用于处理键盘输入事件)、SingleTouchInputMapper(用于处理单点触摸输入事件)、CursorInputMapper( 用于处理鼠标输入事件)等。因为输入设备有很多,因此就会有不同的 InputMapper 来处理不同类型的事件。这里以SingleTouchInputMapper为例,来分析输入事件到底是怎么分发出去的?会省略部分代码,只关注主线。

SingleTouchInputMapper#
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
    //调用父类TouchInputMapper的process
    TouchInputMapper::process(rawEvent);
     mSingleTouchMotionAccumulator.process(rawEvent);
}
TouchInputMapper#
void TouchInputMapper::process(const RawEvent* rawEvent) {
    sync(rawEvent->when);
}

void TouchInputMapper::sync(nsecs_t when) {
    processRawTouches(false /*timeout*/);
}

void TouchInputMapper::processRawTouches(bool timeout) {
    cookAndDispatch(mCurrentRawState.when);
}

void TouchInputMapper::cookAndDispatch(nsecs_t when) {
         //看起来有点像事件的分发方法了
        if (!mCurrentMotionAborted) {
            dispatchButtonRelease(when, policyFlags);
            dispatchHoverExit(when, policyFlags);
            dispatchTouches(when, policyFlags);
            dispatchHoverEnterAndMove(when, policyFlags);
            dispatchButtonPress(when, policyFlags);
        }
    }
}

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
    dispatchMotion(...);
}

void TouchInputMapper::dispatchMotion(...) {
    //将经过加过的事件封装成NotifyMotionArgs
    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, actionButton, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime);
    //调用getListener的notifyMotion方法
    getListener的()->notifyMotion(&args);
}

调用getListener的notifyMotion方法最终会走到InputDispatcher.cpp的notifyMotion方法

InputDispatcher.cpp#
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {

    // Just enqueue a new motion event.
    //将事件进一步封装
   MotionEntry* newEntry = new MotionEntry(args->eventTime,
             args->deviceId, args->source, policyFlags,
             args->action, args->actionButton, args->flags,
             args->metaState, args->buttonState,
             args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
             args->displayId,
             args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
    //将事件插入队列
    needWake = enqueueInboundEventLocked(newEntry);
    
    if (needWake) {
        //如果需要就唤醒InputDispatcherThread
        mLooper->wake();
    }
}

InputDispatcherThread线程被唤醒之后就会对事件进行分发。mLooper怎么救能唤醒InputDispatcherThread呢,

InputDispatcher.cpp#
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    //通过代码可以看出来,它就是InputDispatcher直接new出来的一个成员而已
    mLooper = new Looper(false);
}

mLooper先放放。先来分析下InputDispatcherThread这个线程,前面分析过InputManager在构造时会调用initialize方法,这个方法如下创建了InputDispatcherThread线程,它持有InputDispatcher引用

void InputManager::initialize() {
    //InputDispatcher和InputReader的执行都比较耗时,放到单独的线程中执行。
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
// --- InputDispatcherThread ---
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
        Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}

InputDispatcherThread::~InputDispatcherThread() {
}

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}

它的threadLoop方法直接调了InputDispatcher的dispatchOnce方法。

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = 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()) {
            //这里分发输入事件给window
            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_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    //休眠timeoutMillis时间
    mLooper->pollOnce(timeoutMillis);
}

这里调用了mLooper->pollOnce使InputDispatcherThread休眠, 有两种方法来唤醒mLooper,一是mLooper->wake(),二是nextWakeupTime时间到达后 。

结合前面的分析知道,InputReader读取到输入事件,会把事件通过InputDispatcher的enqueueInboundEventLocked插入队列,然后通过mLooper来唤醒 InputDispatcherThread , InputDispatcherThread 被唤醒后会去分发输入事件给具体的窗口。

到现在InputManagerService的启动已经分析完成了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值