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 Original line Diff line number Diff line
@@ -18,28 +18,28 @@


//#define LOG_NDEBUG 0
//#define LOG_NDEBUG 0


#include <nativehelper/JNIHelp.h>

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


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


#include "core_jni_helpers.h"


using android::base::Result;
using android::base::Result;


namespace android {
namespace android {


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


static struct {
static struct {
    jclass clazz;
    jclass clazz;
@@ -74,8 +74,10 @@ private:
        return mInputPublisher.getChannel()->getName();
        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);
    status_t receiveFinishedSignals(JNIEnv* env);
    bool notifyFinishedSignal(JNIEnv* env, jobject sender, const InputPublisher::Finished& finished,
                              bool skipCallbacks);
};
};


NativeInputEventSender::NativeInputEventSender(JNIEnv* env, jobject senderWeak,
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());
        ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName().c_str());
    }
    }


    ScopedLocalRef<jobject> senderObj(env, NULL);
    ScopedLocalRef<jobject> senderObj(env, jniGetReferent(env, mSenderWeakGlobal));
    bool skipCallbacks = false;
    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 (;;) {
    for (;;) {
        Result<InputPublisher::Finished> result = mInputPublisher.receiveFinishedSignal();
        Result<InputPublisher::Finished> result = mInputPublisher.receiveFinishedSignal();
        if (!result.ok()) {
        if (!result.ok()) {
@@ -210,41 +217,51 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
            return status;
            return status;
        }
        }


        auto it = mPublishedSeqMap.find(result->seq);
        const bool notified = notifyFinishedSignal(env, senderObj.get(), *result, skipCallbacks);
        if (it == mPublishedSeqMap.end()) {
        if (!notified) {
            continue;
            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);
    mPublishedSeqMap.erase(it);


    if (kDebugDispatchCycle) {
    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",
              getInputChannelName().c_str(), seq, finished.handled ? "true" : "false",
              mPublishedSeqMap.size());
              mPublishedSeqMap.size());
    }
    }

    if (skipCallbacks) {
        if (!skipCallbacks) {
        return true;
            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;
                }
    }
    }


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



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


import android.os.HandlerThread
import android.os.HandlerThread
import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
import android.os.Looper
import android.os.Looper
import android.view.InputChannel
import android.view.InputChannel
import android.view.InputEvent
import android.view.InputEvent
@@ -24,7 +25,8 @@ import android.view.InputEventReceiver
import android.view.InputEventSender
import android.view.InputEventSender
import android.view.KeyEvent
import android.view.KeyEvent
import android.view.MotionEvent
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.Assert.assertEquals
import org.junit.After
import org.junit.After
import org.junit.Before
import org.junit.Before
@@ -44,41 +46,44 @@ private fun assertKeyEvent(expected: KeyEvent, received: KeyEvent) {
    assertEquals(expected.displayId, received.displayId)
    assertEquals(expected.displayId, received.displayId)
}
}


class TestInputEventReceiver(channel: InputChannel, looper: Looper) :
private fun <T> getEvent(queue: LinkedBlockingQueue<T>): T {
        InputEventReceiver(channel, looper) {
    try {
    companion object {
        return queue.poll(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong(), TimeUnit.MILLISECONDS)
        const val TAG = "TestInputEventReceiver"
    } 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) {
    override fun onInputEvent(event: InputEvent) {
        lastEvent = when (event) {
        when (event) {
            is KeyEvent -> KeyEvent.obtain(event)
            is KeyEvent -> mInputEvents.put(KeyEvent.obtain(event))
            is MotionEvent -> MotionEvent.obtain(event)
            is MotionEvent -> mInputEvents.put(MotionEvent.obtain(event))
            else -> throw Exception("Received $event is neither a key nor a motion")
            else -> throw Exception("Received $event is neither a key nor a motion")
        }
        }
        finishInputEvent(event, true /*handled*/)
        finishInputEvent(event, true /*handled*/)
    }
    }

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


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

    }
    private val mFinishedSignals = LinkedBlockingQueue<FinishedSignal>()
    data class FinishedResult(val seq: Int, val handled: Boolean)


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


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


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


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


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