Android Touch事件InputManagerService源码解析(一)

Android 常见的 View Touch 事件的分发,相信大家都已经耳熟能详了。但是这是触摸事件的消费处理过程,有没有想过 touch 事件是由谁产生,又是如何传递给 View 的。本文从源码角度浅析一下 Touch 事件的产生过程。

1 InputManagerService 的创建

在系统启动的时候会调用 SystemServer 进行启动并初始化大量的服务

[-> SystemServer.java]

private void startOtherServices() {


        try {
   、、、
            traceBeginAndSlog("StartInputManagerService");
            inputManager = new InputManagerService(context);
            traceEnd();

            traceBeginAndSlog("StartWindowManagerService");
            // WMS needs sensor service ready
            ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
            mSensorServiceStart = null;
            wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
 // 将名为"window"的系统服务添加到Binder大管家ServiceManager,在其他地方就可以通过Context.WINDOW_SERVICE拿到WindowManagerService
            ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
 // 将名为"input"的系统服务添加到Binder大管家ServiceManager,在其他地方就可以通过Context.INPUT_SERVICE拿到InputManagerService
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            traceEnd();

            traceBeginAndSlog("SetWindowManagerService");
            mActivityManagerService.setWindowManager(wm);
            traceEnd();

            traceBeginAndSlog("WindowManagerServiceOnInitReady");
            wm.onInitReady();
            traceEnd();

            // Start receiving calls from HIDL services. Start in in a separate thread
            // because it need to connect to SensorManager. This have to start
            // after START_SENSOR_SERVICE is done.
            SystemServerInitThreadPool.get().submit(() -> {
                TimingsTraceLog traceLog = new TimingsTraceLog(
                        SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
                traceLog.traceBegin(START_HIDL_SERVICES);
                startHidlServices();
                traceLog.traceEnd();
            }, START_HIDL_SERVICES);

            if (!isWatch && enableVrService) {
                traceBeginAndSlog("StartVrManagerService");
                mSystemServiceManager.startService(VrManagerService.class);
                traceEnd();
            }

            traceBeginAndSlog("StartInputManager");
   // 为InputManagerService设置WindowManagerCallbacks,这样WMS与IM就可以互相通信了
            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            inputManager.start();
            traceEnd();
            、、、
        } catch (RuntimeException e) {
            Slog.e("System""******************************************");
            Slog.e("System""************ Failure starting core service", e);
        }
        、、、
}

2 InputManagerService 的初始化

[ -> InputManagerService ]

public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        String doubleTouchGestureEnablePath = context.getResources().getString(
                R.string.config_doubleTouchGestureEnableFile);
        mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
            new File(doubleTouchGestureEnablePath);

        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }

    public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);

        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);
// 通过ContentObserver监听SettingsProvider中input相关设置项的值
        registerPointerSpeedSettingObserver();
        registerShowTouchesSettingObserver();
        registerAccessibilityLargePointerSettingObserver();
// 监听用户切换的广播,并更新SettingsProvider中input相关设置项的值
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updatePointerSpeedFromSettings();
                updateShowTouchesFromSettings();
                updateAccessibilityLargePointerFromSettings();
            }
        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
// InputManagerService创建时会主动触发一次input相关设置项的刷新
        updatePointerSpeedFromSettings();
        updateShowTouchesFromSettings();
        updateAccessibilityLargePointerFromSettings();
    }

nativeInit 与 nativeStart 是 native 的方法 [-> 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 == nullptr) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
//返回一个long类型的指针数据给java层,java层会保存这个数据,在调用NativeInputManager相关的函数时将指针再传回native层
    return reinterpret_cast<jlong>(im);
}

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
//这个ptr就是nativeInit 创建的NativeInputManager实例的指针
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

此时 java 层的 InputManagerService 就与 native 层的 NativeInputManager 建立了联系。

3 native 层 NativeInputManager 初始化

在 1.2 中 native 层创建了一个 NativeInputManager 实例,并将对应指针返回了 java 层,在 nativeStart 的时候又调用了 start 函数。 [-> com_android_server_input_InputManagerService.cpp ]

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerCapture = false;
        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
    }
    mInteractive = true;
//创建InputManager实例,并添加到ServiceManager
    mInputManager = new InputManager(this, this);
    defaultServiceManager()->addService(String16("inputflinger"),
            mInputManager, false);
}

4 InputManager

[ -> InputManager.cpp ]

InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mClassifier = new InputClassifier(mDispatcher);
    mReader = createInputReader(readerPolicy, mClassifier);
    initialize();
}


void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

status_t InputManager::start() {
    status_t result = 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;
}

可以看到 InputDispathcer 和 InputReader 启动了 2 个非常重要的线程,它们确保了 input 子系统能够源源不断的从底层获取输入事件,并将事件经过层层包装之后上报给当前的焦点窗口去处理

InputDispathcer 与 InputReader 内部都有一个线程,不停的调用 loopOnce 函数。

4 Touch 事件的产生

[-> InputReader.cpp]

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock

    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
            processEventsLocked(mEventBuffer, count);
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }

        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
    mQueuedListener->flush();
}

这里有个 EventHub,它主要是利用 Linux 的 inotify 和 epoll 机制,监听设备事件:包括设备插拔及各种触摸、按钮事件等,可以看作是一个不同设备的集线器,主要面向的是/dev/input 目录下的设备节点,比如说/dev/input/event0 上的事件就是输入事件,通过 EventHub 的 getEvents 就可以监听并获取该事件: alt

通过 mEventHub 读取输入到 buffer 内,然后通过一个 processEventsLocked->processEventsForDeviceLocked->Device::process->MultiTouchInputMapper::process->TouchInputMapper::process->TouchInputMapper::sync->TouchInputMapper::processRawTouches->TouchInputMapper::cookAndDispatch->TouchInputMapper::dispatchTouches->TouchInputMapper::dispatchMotion

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
        int32_t action, int32_t actionButton, int32_t flags,
        int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
        const PointerProperties* properties, const PointerCoords* coords,
        const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
        float xPrecision, float yPrecision, nsecs_t downTime) {
    PointerCoords pointerCoords[MAX_POINTERS];
    PointerProperties pointerProperties[MAX_POINTERS];
    uint32_t pointerCount = 0;
    while (!idBits.isEmpty()) {
        uint32_t id = idBits.clearFirstMarkedBit();
        uint32_t index = idToIndex[id];
        pointerProperties[pointerCount].copyFrom(properties[index]);
        pointerCoords[pointerCount].copyFrom(coords[index]);

        if (changedId >= 0 && id == uint32_t(changedId)) {
            action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
        }

        pointerCount += 1;
    }

    ALOG_ASSERT(pointerCount != 0);

    if (changedId >= 0 && pointerCount == 1) {
        // Replace initial down and final up action.
        // We can compare the action without masking off the changed pointer index
        // because we know the index is 0.
        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
            action = AMOTION_EVENT_ACTION_DOWN;
        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
            action = AMOTION_EVENT_ACTION_UP;
        } else {
            // Can't happen.
            ALOG_ASSERT(false);
        }
    }
    const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
    const int32_t deviceId = getDeviceId();
    std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
    std::for_each(frames.begin(), frames.end(),
            [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
    NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
            source, displayId, policyFlags,
            action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
            edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime, std::move(frames));
    getListener()->notifyMotion(&args);
}

getListener()获取的是创建 InputReader 时候传入的参数,InputClassifier 的一个实例 alt

alt
alt

InputClassifier 又将事件传给了 mListener,也就是 InputDispatcher,此时 touch 事件由 InputReader(生产者),传递给了 InputDispatcher(分发者)。

5 总结

系统在启动的时候 SystemServer 会启动 InputManagerService 与 WindowManagerService,并且会建立两者的联系。InputManagerService 在初始化的时候会在 native 层 NativeInputManager 实例,并且启动 NativeInputManager。NativeInputManager 又会创建 InputManager,InputManager 才是事件的产生&分发事件的实际执行者。 InputManager 内有一个 InputReader 与 InputDispatcher 实例,两个对象分别运行在一个单独线程内,负责事件的读取产生与分发工作。InputReader 在从 EventHub 从各个 device 节点读取到事件后收集起来通过接口回调抛给 InputDispatcher。

参考:https://www.jianshu.com/p/9cb9f8e0747e?u_atoken=f20541b3-3b4e-4c34-b727-2a455aff4664&u_asession=01M6ybYhbRKxvmPzfNbiaqibNZyGyCf_tHM56zly_ytD8e2jpgJMh2wVTR7_5qEvIbX0KNBwm7Lovlpxjd_P_q4JsKWYrT3W_NKPr8w6oU7K-NYWoPylB52eK6uInj8loJdSd2xtyR8tGtAryp6pbvRmBkFo3NEHBv0PZUm6pbxQU&u_asig=05oEbVwSzUZF-mtwraded9ESuH0nb-Om3UNDFQKBAF894K4knwyS7AeMXnwt2rMaMfDvSEWLgfR0JSBIpd6X-xisXQLbaUSsaHVtus4aAEz930cJFH-C6GFWEpkvGhP5-jBhtwBl2AKd3-DXyYTClh5FF6oDwZ4M1Chh5Ng1BKeGv9JS7q8ZD7Xtz2Ly-b0kmuyAKRFSVJkkdwVUnyHAIJzbj-vEZmPY1C4YdKk8LG8lTwLD6Rfm4Yex9MudGNq18owt74LEzKVH73PIwzPMOHf-3h9VXwMyh6PgyDIVSG1W_Ed0voG6Z-DmzL1dJBoPfFntxszIC-jZ3XnMw67JPJQ966s6TWGwj4LMqIXLFq9Afz-O_L4kbFOysbTX64_WBOmWspDxyAEEo4kbsryBKb9Q&u_aref=Mqq/rQDhTN5Xjiw7coT0SfQEsbE=

本文由 mdnice 多平台发布

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值