Merge "Process output events in a separate function" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-03-04 02:00:56 +00:00
committed by Android (Google) Code Review

View File

@@ -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;
@@ -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,
@@ -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)
@@ -179,10 +200,61 @@ void NativeInputEventReceiver::setFdEvents(int events) {
}
}
/**
* 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) {
// 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' ~ Remaining outbound events: %zu.",
getInputChannelName().c_str(), mFinishQueue.size());
}
return HandleEventResponse::KEEP_CALLBACK; // try again later
}
// 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 send outbound event. status=%d",
status);
jniThrowRuntimeException(env, message.c_str());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
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) {
// 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
@@ -191,56 +263,25 @@ int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data)
ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. "
"events=0x%x", getInputChannelName().c_str(), events);
}
return REMOVE_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 ? KEEP_CALLBACK : REMOVE_CALLBACK;
return status == OK || status == NO_MEMORY
? toUnderlying(HandleEventResponse::KEEP_CALLBACK)
: toUnderlying(HandleEventResponse::REMOVE_CALLBACK);
}
if (events & ALOOPER_EVENT_OUTPUT) {
for (size_t i = 0; i < mFinishQueue.size(); i++) {
const Finish& finish = mFinishQueue[i];
status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
if (status != OK) {
mFinishQueue.erase(mFinishQueue.begin(), mFinishQueue.begin() + i);
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
getInputChannelName().c_str(), i, mFinishQueue.size());
}
return KEEP_CALLBACK; // try again later
}
ALOGW("Failed to send finished signal 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",
status);
jniThrowRuntimeException(env, message.c_str());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
return REMOVE_CALLBACK;
}
}
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; none left.",
getInputChannelName().c_str(), mFinishQueue.size());
}
mFinishQueue.clear();
setFdEvents(ALOOPER_EVENT_INPUT);
return KEEP_CALLBACK;
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,