当前位置: 首页 > article >正文

Android—IMS的InputReader

 在startOtherServices中

frameworks\base\services\java\com\android\server\SystemServer.java:

            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);
            ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            traceEnd();

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

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

            ...

            traceBeginAndSlog("StartInputManager");
            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            inputManager.start();
            traceEnd();

会先去创建IMS,再去创建启动WMS,因为双方需要合作,IMS接受各种input事件,发送到WMS的各个窗口。 最好WMS准备好之后启动IMS。

我们先看IMS的构造函数:

frameworks\base\services\core\java\com\android\server\input\InputManagerService.java:

    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());
    }

1. this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

2. mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

Handler可能是用来处理某种Msg,我们可以先不用管,找到对应的Msg再看。

先看nativeInit,注意:该方法将Handler的MsgQueue作为参数传入,意味着后面可能就是在Native层发送信息到改队列中,由IMS的Handler进行处理。

frameworks\base\services\core\jni\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);
    return reinterpret_cast<jlong>(im);
}

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;

    mInputManager = new InputManager(this, this);
    defaultServiceManager()->addService(String16("inputflinger"),
            mInputManager, false);
}

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

sp<InputReaderInterface> createInputReader(
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) {
    return new InputReader(new EventHub(), policy, listener);
}

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

 这里创建了NativeInputManager -> InputManger -> InputReaderThread、InputDispatcherThread

现在要搞清楚InputReaderThread、InputDispatcherThread是干啥的。

回到一开始我们知道创建完IMS,然后等WMS准备完成后会启动IMS。

            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            inputManager.start();

frameworks\base\services\core\java\com\android\server\input\InputManagerService.java:

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

frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp:

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

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

frameworks\native\services\inputflinger\InputManager.cpp:

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;
}

 mDispatcherThread和mReaderThread都集成了Thread,这里调用了run方法会调用到threadLoop,threadLoop返回false会退出循环,true则继续循环,这里涉及的知识点大家可以另外查找。

我们先看mReaderThread

frameworks\native\services\inputflinger\InputReaderBase.cpp:

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

frameworks\native\services\inputflinger\InputReader.cpp:

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
    ....
    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;
            }
#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

忽略掉一些代码,可以看出这里从EventHub中获取input事件,然后调用

1.processEventsLocked(mEventBuffer, count);

2.mQueuedListener->flush();

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

1.processEventsLocked(mEventBuffer, count);

processEventsLocked里面区分了输入事件的处理,输入设备的处理。我们只看输入事件的处理。

processEventsForDeviceLocked里面的流程比较长,这里代码就不列出来,主要的流程就是:

processEventsForDeviceLocked->process->KeyboardInputMapper::process->processKey->QueuedInputListener::notifyKey

frameworks\native\services\inputflinger\InputListener.cpp:

void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
    mArgsQueue.push_back(new NotifyKeyArgs(*args));
}

 mArgsQueue是Vector队列,在尾部插入 。

2.mQueuedListener->flush();

frameworks\native\services\inputflinger\InputListener.cpp:

void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);
        delete args;
    }
    mArgsQueue.clear();
}

void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifyKey(this);
}

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

从之前创建InputReader的地方我们知道这里的listener是InputClassifier

void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
    // pass through
    mListener->notifyKey(args);
}

InputClassifier的mListener是mDispatcher

frameworks\native\services\inputflinger\InputDispatcher.cpp:

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
    ...
    bool needWake;
    { // acquire lock
        mLock.lock();
        ...
        KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime,
                args->deviceId, args->source, args->displayId, policyFlags,
                args->action, flags, keyCode, args->scanCode,
                metaState, repeatCount, args->downTime);

        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock

    if (needWake) {
        mLooper->wake();
    }
}

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

    switch (entry->type) {
    case EventEntry::TYPE_KEY: {
        // Optimize app switch latency.
        // If the application takes too long to catch up then we drop all events preceding
        // the app switch key.
        KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
        if (isAppSwitchKeyEvent(keyEntry)) {
            if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
                mAppSwitchSawKeyDown = true;
            } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
                if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
                    ALOGD("App switch is pending!");
#endif
                    mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
                    mAppSwitchSawKeyDown = false;
                    needWake = true;
                }
            }
        }
        break;
    }

    case EventEntry::TYPE_MOTION: {
        // Optimize case where the current application is unresponsive and the user
        // decides to touch a window in a different application.
        // If the application takes too long to catch up then we drop all events preceding
        // the touch into the other window.
        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
        if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
                && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
                && mInputTargetWaitApplicationToken != nullptr) {
            int32_t displayId = motionEntry->displayId;
            int32_t x = int32_t(motionEntry->pointerCoords[0].
                    getAxisValue(AMOTION_EVENT_AXIS_X));
            int32_t y = int32_t(motionEntry->pointerCoords[0].
                    getAxisValue(AMOTION_EVENT_AXIS_Y));
            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
            if (touchedWindowHandle != nullptr
                    && touchedWindowHandle->getApplicationToken()
                            != mInputTargetWaitApplicationToken) {
                // User touched a different application than the one we are waiting on.
                // Flag the event, and start pruning the input queue.
                mNextUnblockedEvent = motionEntry;
                needWake = true;
            }
        }
        break;
    }
    }

    return needWake;
}

notifyKey最终将数据封装成KeyEntry然后添加到mInboundQueue队尾,然后唤醒Looper。

所以processEventsLocked(mEventBuffer, count)就是去添加事件到队列,mQueuedListener->flush();就是去唤醒InputDispatcher去处理事件。


http://www.kler.cn/a/10280.html

相关文章:

  • Servlet入门 Servlet生命周期 Servlet体系结构
  • SQL集合运算
  • SystemVerilog学习笔记(六):控制流
  • 车-路-站-网”信息耦合的汽车有序充电
  • 21. Drag-Drop拖放操作(二) - 文件、表格和树的拖放实现
  • pySpark乱码
  • 单片机程序是如何运行起来
  • python+vue+ 疫情冷链追溯管理系统
  • 数字中国理念引领国企人力资源数字化转型与实践
  • 2.29、共享内存(2)
  • Springboot整合Quartz实现定时任务数据库动态配置
  • Python数据分析:轻松实现数据处理、分析和可视化的入门教程
  • 代码自动发布系统
  • qt - 隐式共享与d-pointer技术
  • Android 11.0 原生SystemUI下拉通知栏UI背景设置为圆角背景的定制(二)
  • ptuning v2 的 chatglm垂直领域训练记录
  • 银行数字化转型导师坚鹏:金融科技与数字化转型成功案例
  • 腾讯云服务器TencentOS系统安装宝塔Linux面板命令
  • 软件管理 基础配置(运维笔记)
  • 所有知识付费都可以用 ChatGPT 再割一次?
  • 设计师都在用的6个免费设计素材网站~
  • 【C++】内联函数理解
  • d修复导入c的问题
  • MySQL日志
  • 如何驯化生成式AI,从提示工程 Prompt Engineering 开始
  • Day939.如何小步安全地升级数据库框架 -系统重构实战