Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3abddab6 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Move 'notifyFinishedSignal' into a separate function" into sc-dev am: 49148d76

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13932458

Change-Id: I48c695c487e81ce8c0a12c11fd42db5fa89be4d9
parents 0768d999 49148d76
Loading
Loading
Loading
Loading
+56 −39
Original line number Diff line number Diff line
@@ -18,28 +18,28 @@

//#define LOG_NDEBUG 0

#include <nativehelper/JNIHelp.h>

#include <android_runtime/AndroidRuntime.h>
#include <input/InputTransport.h>
#include <log/log.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <utils/Looper.h>
#include <input/InputTransport.h>
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
#include "android_view_MotionEvent.h"
#include "core_jni_helpers.h"

#include <nativehelper/ScopedLocalRef.h>
#include <inttypes.h>
#include <unordered_map>

#include "core_jni_helpers.h"

using android::base::Result;

namespace android {

// Log debug messages about the dispatch cycle.
static const bool kDebugDispatchCycle = false;
static constexpr bool kDebugDispatchCycle = false;

static struct {
    jclass clazz;
@@ -74,8 +74,10 @@ private:
        return mInputPublisher.getChannel()->getName();
    }

    virtual int handleEvent(int receiveFd, int events, void* data);
    int handleEvent(int receiveFd, int events, void* data) override;
    status_t receiveFinishedSignals(JNIEnv* env);
    bool notifyFinishedSignal(JNIEnv* env, jobject sender, const InputPublisher::Finished& finished,
                              bool skipCallbacks);
};

NativeInputEventSender::NativeInputEventSender(JNIEnv* env, jobject senderWeak,
@@ -196,8 +198,13 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
        ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName().c_str());
    }

    ScopedLocalRef<jobject> senderObj(env, NULL);
    bool skipCallbacks = false;
    ScopedLocalRef<jobject> senderObj(env, jniGetReferent(env, mSenderWeakGlobal));
    if (!senderObj.get()) {
        ALOGW("channel '%s' ~ Sender object was finalized without being disposed.",
              getInputChannelName().c_str());
        return DEAD_OBJECT;
    }
    bool skipCallbacks = false; // stop calling Java functions after an exception occurs
    for (;;) {
        Result<InputPublisher::Finished> result = mInputPublisher.receiveFinishedSignal();
        if (!result.ok()) {
@@ -210,41 +217,51 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
            return status;
        }

        auto it = mPublishedSeqMap.find(result->seq);
        if (it == mPublishedSeqMap.end()) {
            continue;
        const bool notified = notifyFinishedSignal(env, senderObj.get(), *result, skipCallbacks);
        if (!notified) {
            skipCallbacks = true;
        }
    }
}

        uint32_t seq = it->second;
/**
 * Invoke the Java function dispatchInputEventFinished for the received "Finished" signal.
 * Set the variable 'skipCallbacks' to 'true' if a Java exception occurred.
 * Java function will only be called if 'skipCallbacks' is originally 'false'.
 *
 * Return "false" if an exception occurred while calling the Java function
 *        "true" otherwise
 */
bool NativeInputEventSender::notifyFinishedSignal(JNIEnv* env, jobject sender,
                                                  const InputPublisher::Finished& finished,
                                                  bool skipCallbacks) {
    auto it = mPublishedSeqMap.find(finished.seq);
    if (it == mPublishedSeqMap.end()) {
        ALOGW("Received 'finished' signal for unknown seq number = %" PRIu32, finished.seq);
        // Since this is coming from the receiver (typically app), it's possible that an app
        // does something wrong and sends bad data. Just ignore and process other events.
        return true;
    }
    const uint32_t seq = it->second;
    mPublishedSeqMap.erase(it);

    if (kDebugDispatchCycle) {
        ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, pendingEvents=%zu.",
                  getInputChannelName().c_str(), seq, result->handled ? "true" : "false",
              getInputChannelName().c_str(), seq, finished.handled ? "true" : "false",
              mPublishedSeqMap.size());
    }

        if (!skipCallbacks) {
            if (!senderObj.get()) {
                senderObj.reset(jniGetReferent(env, mSenderWeakGlobal));
                if (!senderObj.get()) {
                    ALOGW("channel '%s' ~ Sender object was finalized without being disposed.",
                          getInputChannelName().c_str());
                    return DEAD_OBJECT;
                }
    if (skipCallbacks) {
        return true;
    }

            env->CallVoidMethod(senderObj.get(),
                                gInputEventSenderClassInfo.dispatchInputEventFinished,
                                static_cast<jint>(seq), static_cast<jboolean>(result->handled));
    env->CallVoidMethod(sender, gInputEventSenderClassInfo.dispatchInputEventFinished,
                        static_cast<jint>(seq), static_cast<jboolean>(finished.handled));
    if (env->ExceptionCheck()) {
                ALOGE("Exception dispatching finished signal.");
                skipCallbacks = true;
            }
        ALOGE("Exception dispatching finished signal for seq=%" PRIu32, seq);
        return false;
    }
    return true;
}
}


static jlong nativeInit(JNIEnv* env, jclass clazz, jobject senderWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
+29 −24
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.test.input

import android.os.HandlerThread
import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
import android.os.Looper
import android.view.InputChannel
import android.view.InputEvent
@@ -24,7 +25,8 @@ import android.view.InputEventReceiver
import android.view.InputEventSender
import android.view.KeyEvent
import android.view.MotionEvent
import java.util.concurrent.CountDownLatch
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
import org.junit.Assert.assertEquals
import org.junit.After
import org.junit.Before
@@ -44,41 +46,44 @@ private fun assertKeyEvent(expected: KeyEvent, received: KeyEvent) {
    assertEquals(expected.displayId, received.displayId)
}

class TestInputEventReceiver(channel: InputChannel, looper: Looper) :
        InputEventReceiver(channel, looper) {
    companion object {
        const val TAG = "TestInputEventReceiver"
private fun <T> getEvent(queue: LinkedBlockingQueue<T>): T {
    try {
        return queue.poll(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong(), TimeUnit.MILLISECONDS)
    } catch (e: InterruptedException) {
        throw RuntimeException("Unexpectedly interrupted while waiting for event")
    }
}

    var lastEvent: InputEvent? = null
class TestInputEventReceiver(channel: InputChannel, looper: Looper) :
        InputEventReceiver(channel, looper) {
    private val mInputEvents = LinkedBlockingQueue<InputEvent>()

    override fun onInputEvent(event: InputEvent) {
        lastEvent = when (event) {
            is KeyEvent -> KeyEvent.obtain(event)
            is MotionEvent -> MotionEvent.obtain(event)
        when (event) {
            is KeyEvent -> mInputEvents.put(KeyEvent.obtain(event))
            is MotionEvent -> mInputEvents.put(MotionEvent.obtain(event))
            else -> throw Exception("Received $event is neither a key nor a motion")
        }
        finishInputEvent(event, true /*handled*/)
    }

    fun getInputEvent(): InputEvent {
        return getEvent(mInputEvents)
    }
}

class TestInputEventSender(channel: InputChannel, looper: Looper) :
        InputEventSender(channel, looper) {
    companion object {
        const val TAG = "TestInputEventSender"
    }
    data class FinishedResult(val seq: Int, val handled: Boolean)
    data class FinishedSignal(val seq: Int, val handled: Boolean)

    private val mFinishedSignals = LinkedBlockingQueue<FinishedSignal>()

    private var mFinishedSignal = CountDownLatch(1)
    override fun onInputEventFinished(seq: Int, handled: Boolean) {
        finishedResult = FinishedResult(seq, handled)
        mFinishedSignal.countDown()
        mFinishedSignals.put(FinishedSignal(seq, handled))
    }
    lateinit var finishedResult: FinishedResult

    fun waitForFinish() {
        mFinishedSignal.await()
        mFinishedSignal = CountDownLatch(1) // Ready for next event
    fun getFinishedSignal(): FinishedSignal {
        return getEvent(mFinishedSignals)
    }
}

@@ -111,13 +116,13 @@ class InputEventSenderAndReceiverTest {
                KeyEvent.KEYCODE_A, 0 /*repeat*/)
        val seq = 10
        mSender.sendInputEvent(seq, key)
        mSender.waitForFinish()
        val receivedKey = mReceiver.getInputEvent() as KeyEvent
        val finishedSignal = mSender.getFinishedSignal()

        // Check receiver
        assertKeyEvent(key, mReceiver.lastEvent!! as KeyEvent)
        assertKeyEvent(key, receivedKey)

        // Check sender
        assertEquals(seq, mSender.finishedResult.seq)
        assertEquals(true, mSender.finishedResult.handled)
        assertEquals(TestInputEventSender.FinishedSignal(seq, handled = true), finishedSignal)
    }
}