Merge "Send events from InputEventReceiver in order" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-03-16 02:30:51 +00:00
committed by Android (Google) Code Review
2 changed files with 42 additions and 64 deletions

View File

@@ -45,12 +45,6 @@ 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;
@@ -77,14 +71,6 @@ 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,
@@ -121,16 +107,11 @@ private:
return mInputConsumer.getChannel()->getName();
}
HandleEventResponse processOutboundEvents();
status_t 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)
@@ -167,26 +148,12 @@ status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled)
ALOGD("channel '%s' ~ Finished input event.", getInputChannelName().c_str());
}
status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
if (status != OK) {
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Could not send finished signal immediately. "
"Enqueued for later.", getInputChannelName().c_str());
}
Finish finish;
finish.seq = seq;
finish.handled = handled;
mFinishQueue.push_back(finish);
if (mFinishQueue.size() == 1) {
setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
}
return OK;
}
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
getInputChannelName().c_str(), status);
}
return status;
Finish finish{
.seq = seq,
.handled = handled,
};
mFinishQueue.push_back(finish);
return processOutboundEvents();
}
void NativeInputEventReceiver::setFdEvents(int events) {
@@ -217,7 +184,7 @@ void NativeInputEventReceiver::setFdEvents(int events) {
* InputPublisher. If no events are remaining, let the looper know so that it doesn't wake up
* unnecessarily.
*/
HandleEventResponse NativeInputEventReceiver::processOutboundEvents() {
status_t NativeInputEventReceiver::processOutboundEvents() {
while (!mFinishQueue.empty()) {
const Finish& finish = *mFinishQueue.begin();
status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
@@ -233,7 +200,8 @@ HandleEventResponse NativeInputEventReceiver::processOutboundEvents() {
ALOGD("channel '%s' ~ Remaining outbound events: %zu.",
getInputChannelName().c_str(), mFinishQueue.size());
}
return HandleEventResponse::KEEP_CALLBACK; // try again later
setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
return WOULD_BLOCK; // try again later
}
// Some other error. Give up
@@ -247,42 +215,49 @@ HandleEventResponse NativeInputEventReceiver::processOutboundEvents() {
jniThrowRuntimeException(env, message.c_str());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
return HandleEventResponse::REMOVE_CALLBACK;
return status;
}
// The queue is now empty. Tell looper there's no more output to expect.
setFdEvents(ALOOPER_EVENT_INPUT);
return HandleEventResponse::KEEP_CALLBACK;
return OK;
}
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);
ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. events=0x%x",
getInputChannelName().c_str(), events);
}
return toUnderlying(HandleEventResponse::REMOVE_CALLBACK);
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
? toUnderlying(HandleEventResponse::KEEP_CALLBACK)
: toUnderlying(HandleEventResponse::REMOVE_CALLBACK);
return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
}
if (events & ALOOPER_EVENT_OUTPUT) {
return toUnderlying(processOutboundEvents());
const status_t status = processOutboundEvents();
if (status == OK || status == WOULD_BLOCK) {
return KEEP_CALLBACK;
} else {
return REMOVE_CALLBACK;
}
}
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", getInputChannelName().c_str(), events);
return toUnderlying(HandleEventResponse::KEEP_CALLBACK);
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. events=0x%x",
getInputChannelName().c_str(), events);
return KEEP_CALLBACK;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
@@ -503,9 +478,13 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
sp<NativeInputEventReceiver> receiver =
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
status_t status = receiver->finishInputEvent(seq, handled);
if (status && status != DEAD_OBJECT) {
if (status == OK || status == WOULD_BLOCK) {
return; // normal operation
}
if (status != DEAD_OBJECT) {
std::string message =
android::base::StringPrintf("Failed to finish input event. status=%d", status);
android::base::StringPrintf("Failed to finish input event. status=%s(%d)",
strerror(-status), status);
jniThrowRuntimeException(env, message.c_str());
}
}

View File

@@ -172,16 +172,16 @@ int NativeInputEventSender::handleEvent(int receiveFd, int events, void* data) {
// as part of finishing an IME session, in which case the publisher will
// soon be disposed as well.
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", getInputChannelName().c_str(), events);
ALOGD("channel '%s' ~ Consumer closed input channel or an error occurred. events=0x%x",
getInputChannelName().c_str(), events);
}
return 0; // remove the callback
}
if (!(events & ALOOPER_EVENT_INPUT)) {
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", getInputChannelName().c_str(), events);
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. events=0x%x",
getInputChannelName().c_str(), events);
return 1;
}
@@ -219,8 +219,7 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
mPublishedSeqMap.erase(it);
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, "
"pendingEvents=%zu.",
ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, pendingEvents=%zu.",
getInputChannelName().c_str(), seq, result->handled ? "true" : "false",
mPublishedSeqMap.size());
}
@@ -229,8 +228,8 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
if (!senderObj.get()) {
senderObj.reset(jniGetReferent(env, mSenderWeakGlobal));
if (!senderObj.get()) {
ALOGW("channel '%s' ~ Sender object was finalized "
"without being disposed.", getInputChannelName().c_str());
ALOGW("channel '%s' ~ Sender object was finalized without being disposed.",
getInputChannelName().c_str());
return DEAD_OBJECT;
}
}