Loading core/jni/android_view_InputEventReceiver.cpp +82 −41 Original line number Diff line number Diff line Loading @@ -45,6 +45,12 @@ static const char* toString(bool value) { return value ? "true" : "false"; } enum class HandleEventResponse : int { // Allowed return values of 'handleEvent' function as documented in LooperCallback::handleEvent REMOVE_CALLBACK = 0, KEEP_CALLBACK = 1 }; static struct { jclass clazz; Loading @@ -70,6 +76,14 @@ static std::string addPrefix(std::string str, std::string_view prefix) { return str; } /** * Convert an enumeration to its underlying type. Replace with std::to_underlying when available. */ template <class T> static std::underlying_type_t<T> toUnderlying(const T& t) { return static_cast<std::underlying_type_t<T>>(t); } class NativeInputEventReceiver : public LooperCallback { public: NativeInputEventReceiver(JNIEnv* env, jobject receiverWeak, Loading Loading @@ -106,9 +120,16 @@ private: return mInputConsumer.getChannel()->getName(); } virtual int handleEvent(int receiveFd, int events, void* data) override; HandleEventResponse processOutboundEvents(); // From 'LooperCallback' int handleEvent(int receiveFd, int events, void* data) override; }; // Ensure HandleEventResponse underlying type matches the return type of LooperCallback::handleEvent static_assert(std::is_same<std::underlying_type_t<HandleEventResponse>, std::invoke_result_t<decltype(&LooperCallback::handleEvent), NativeInputEventReceiver, int, int, void*>>::value); NativeInputEventReceiver::NativeInputEventReceiver( JNIEnv* env, jobject receiverWeak, const std::shared_ptr<InputChannel>& inputChannel, const sp<MessageQueue>& messageQueue) Loading Loading @@ -179,68 +200,88 @@ void NativeInputEventReceiver::setFdEvents(int events) { } } int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { // Allowed return values of this function as documented in LooperCallback::handleEvent constexpr int REMOVE_CALLBACK = 0; constexpr int KEEP_CALLBACK = 1; if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { // This error typically occurs when the publisher has closed the input channel // as part of removing a window or finishing an IME session, in which case // the consumer will soon be disposed as well. if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. " "events=0x%x", getInputChannelName().c_str(), events); } return REMOVE_CALLBACK; } if (events & ALOOPER_EVENT_INPUT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr); mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK; } if (events & ALOOPER_EVENT_OUTPUT) { for (size_t i = 0; i < mFinishQueue.size(); i++) { const Finish& finish = mFinishQueue[i]; /** * Receiver's primary role is to receive input events, but it has an additional duty of sending * 'ack' for events (using the call 'finishInputEvent'). * * If we are looking at the communication between InputPublisher and InputConsumer, we can say that * from the InputConsumer's perspective, InputMessage's that are sent from publisher to consumer are * called 'inbound / incoming' events, and the InputMessage's sent from InputConsumer to * InputPublisher are 'outbound / outgoing' events. * * NativeInputEventReceiver owns (and acts like) an InputConsumer. So the finish events are outbound * from InputEventReceiver (and will be sent to the InputPublisher). * * In this function, send as many events from 'mFinishQueue' as possible across the socket to the * InputPublisher. If no events are remaining, let the looper know so that it doesn't wake up * unnecessarily. */ HandleEventResponse NativeInputEventReceiver::processOutboundEvents() { while (!mFinishQueue.empty()) { const Finish& finish = *mFinishQueue.begin(); status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled); if (status != OK) { mFinishQueue.erase(mFinishQueue.begin(), mFinishQueue.begin() + i); if (status == OK) { // Successful send. Erase the entry and keep trying to send more mFinishQueue.erase(mFinishQueue.begin()); continue; } // Publisher is busy, try again later. Keep this entry (do not erase) if (status == WOULD_BLOCK) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.", getInputChannelName().c_str(), i, mFinishQueue.size()); ALOGD("channel '%s' ~ Remaining outbound events: %zu.", getInputChannelName().c_str(), mFinishQueue.size()); } return KEEP_CALLBACK; // try again later return HandleEventResponse::KEEP_CALLBACK; // try again later } ALOGW("Failed to send finished signal on channel '%s'. status=%d", // Some other error. Give up ALOGW("Failed to send outbound event on channel '%s'. status=%d", getInputChannelName().c_str(), status); if (status != DEAD_OBJECT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); std::string message = android::base::StringPrintf("Failed to finish input event. status=%d", android::base::StringPrintf("Failed to send outbound event. status=%d", status); jniThrowRuntimeException(env, message.c_str()); mMessageQueue->raiseAndClearException(env, "finishInputEvent"); } return REMOVE_CALLBACK; return HandleEventResponse::REMOVE_CALLBACK; } // The queue is now empty. Tell looper there's no more output to expect. setFdEvents(ALOOPER_EVENT_INPUT); return HandleEventResponse::KEEP_CALLBACK; } int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { // This error typically occurs when the publisher has closed the input channel // as part of removing a window or finishing an IME session, in which case // the consumer will soon be disposed as well. if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Sent %zu queued finish events; none left.", getInputChannelName().c_str(), mFinishQueue.size()); ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. " "events=0x%x", getInputChannelName().c_str(), events); } mFinishQueue.clear(); setFdEvents(ALOOPER_EVENT_INPUT); return KEEP_CALLBACK; return toUnderlying(HandleEventResponse::REMOVE_CALLBACK); } if (events & ALOOPER_EVENT_INPUT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr); mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); return status == OK || status == NO_MEMORY ? toUnderlying(HandleEventResponse::KEEP_CALLBACK) : toUnderlying(HandleEventResponse::REMOVE_CALLBACK); } if (events & ALOOPER_EVENT_OUTPUT) { return toUnderlying(processOutboundEvents()); } ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " "events=0x%x", getInputChannelName().c_str(), events); return KEEP_CALLBACK; return toUnderlying(HandleEventResponse::KEEP_CALLBACK); } status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, Loading Loading
core/jni/android_view_InputEventReceiver.cpp +82 −41 Original line number Diff line number Diff line Loading @@ -45,6 +45,12 @@ static const char* toString(bool value) { return value ? "true" : "false"; } enum class HandleEventResponse : int { // Allowed return values of 'handleEvent' function as documented in LooperCallback::handleEvent REMOVE_CALLBACK = 0, KEEP_CALLBACK = 1 }; static struct { jclass clazz; Loading @@ -70,6 +76,14 @@ static std::string addPrefix(std::string str, std::string_view prefix) { return str; } /** * Convert an enumeration to its underlying type. Replace with std::to_underlying when available. */ template <class T> static std::underlying_type_t<T> toUnderlying(const T& t) { return static_cast<std::underlying_type_t<T>>(t); } class NativeInputEventReceiver : public LooperCallback { public: NativeInputEventReceiver(JNIEnv* env, jobject receiverWeak, Loading Loading @@ -106,9 +120,16 @@ private: return mInputConsumer.getChannel()->getName(); } virtual int handleEvent(int receiveFd, int events, void* data) override; HandleEventResponse processOutboundEvents(); // From 'LooperCallback' int handleEvent(int receiveFd, int events, void* data) override; }; // Ensure HandleEventResponse underlying type matches the return type of LooperCallback::handleEvent static_assert(std::is_same<std::underlying_type_t<HandleEventResponse>, std::invoke_result_t<decltype(&LooperCallback::handleEvent), NativeInputEventReceiver, int, int, void*>>::value); NativeInputEventReceiver::NativeInputEventReceiver( JNIEnv* env, jobject receiverWeak, const std::shared_ptr<InputChannel>& inputChannel, const sp<MessageQueue>& messageQueue) Loading Loading @@ -179,68 +200,88 @@ void NativeInputEventReceiver::setFdEvents(int events) { } } int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { // Allowed return values of this function as documented in LooperCallback::handleEvent constexpr int REMOVE_CALLBACK = 0; constexpr int KEEP_CALLBACK = 1; if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { // This error typically occurs when the publisher has closed the input channel // as part of removing a window or finishing an IME session, in which case // the consumer will soon be disposed as well. if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. " "events=0x%x", getInputChannelName().c_str(), events); } return REMOVE_CALLBACK; } if (events & ALOOPER_EVENT_INPUT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr); mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK; } if (events & ALOOPER_EVENT_OUTPUT) { for (size_t i = 0; i < mFinishQueue.size(); i++) { const Finish& finish = mFinishQueue[i]; /** * Receiver's primary role is to receive input events, but it has an additional duty of sending * 'ack' for events (using the call 'finishInputEvent'). * * If we are looking at the communication between InputPublisher and InputConsumer, we can say that * from the InputConsumer's perspective, InputMessage's that are sent from publisher to consumer are * called 'inbound / incoming' events, and the InputMessage's sent from InputConsumer to * InputPublisher are 'outbound / outgoing' events. * * NativeInputEventReceiver owns (and acts like) an InputConsumer. So the finish events are outbound * from InputEventReceiver (and will be sent to the InputPublisher). * * In this function, send as many events from 'mFinishQueue' as possible across the socket to the * InputPublisher. If no events are remaining, let the looper know so that it doesn't wake up * unnecessarily. */ HandleEventResponse NativeInputEventReceiver::processOutboundEvents() { while (!mFinishQueue.empty()) { const Finish& finish = *mFinishQueue.begin(); status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled); if (status != OK) { mFinishQueue.erase(mFinishQueue.begin(), mFinishQueue.begin() + i); if (status == OK) { // Successful send. Erase the entry and keep trying to send more mFinishQueue.erase(mFinishQueue.begin()); continue; } // Publisher is busy, try again later. Keep this entry (do not erase) if (status == WOULD_BLOCK) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.", getInputChannelName().c_str(), i, mFinishQueue.size()); ALOGD("channel '%s' ~ Remaining outbound events: %zu.", getInputChannelName().c_str(), mFinishQueue.size()); } return KEEP_CALLBACK; // try again later return HandleEventResponse::KEEP_CALLBACK; // try again later } ALOGW("Failed to send finished signal on channel '%s'. status=%d", // Some other error. Give up ALOGW("Failed to send outbound event on channel '%s'. status=%d", getInputChannelName().c_str(), status); if (status != DEAD_OBJECT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); std::string message = android::base::StringPrintf("Failed to finish input event. status=%d", android::base::StringPrintf("Failed to send outbound event. status=%d", status); jniThrowRuntimeException(env, message.c_str()); mMessageQueue->raiseAndClearException(env, "finishInputEvent"); } return REMOVE_CALLBACK; return HandleEventResponse::REMOVE_CALLBACK; } // The queue is now empty. Tell looper there's no more output to expect. setFdEvents(ALOOPER_EVENT_INPUT); return HandleEventResponse::KEEP_CALLBACK; } int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { // This error typically occurs when the publisher has closed the input channel // as part of removing a window or finishing an IME session, in which case // the consumer will soon be disposed as well. if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Sent %zu queued finish events; none left.", getInputChannelName().c_str(), mFinishQueue.size()); ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. " "events=0x%x", getInputChannelName().c_str(), events); } mFinishQueue.clear(); setFdEvents(ALOOPER_EVENT_INPUT); return KEEP_CALLBACK; return toUnderlying(HandleEventResponse::REMOVE_CALLBACK); } if (events & ALOOPER_EVENT_INPUT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr); mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); return status == OK || status == NO_MEMORY ? toUnderlying(HandleEventResponse::KEEP_CALLBACK) : toUnderlying(HandleEventResponse::REMOVE_CALLBACK); } if (events & ALOOPER_EVENT_OUTPUT) { return toUnderlying(processOutboundEvents()); } ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " "events=0x%x", getInputChannelName().c_str(), events); return KEEP_CALLBACK; return toUnderlying(HandleEventResponse::KEEP_CALLBACK); } status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, Loading