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

Commit d472dc84 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Allow sendMotionEvent from any thread

Before this CL, sendMotionEvent was only allowed to be called from the
looper thread. However, this was not enforced in any way. This led to
bugs where the event may not be added to the internal queue of
NativeInputEventSender yet, but the fd is already getting processed and
therefore the received event was dropped without any error.

One option to fix this is to simply raise Exception when the call
happens on the wrong thread. However, that still puts the burden on the
caller to figure out how to call it properly.

Instead, in this CL, allow this method to be called on any thread.
If it's called on the looper thread, then great - return the result
immediately.

If it's called on another thread, then create a Handler and post a
future to the looper thread. Then wait indefinitely until the action is
executed on the looper thread, and return the result in the original
thread.

Bug: 290931418
Test: atest PointerEventDispatcherTest --rerun-until-failure 1000
Change-Id: I39396a8d04e73c090e7d71feafc734075ed27867
parent 86a2352b
Loading
Loading
Loading
Loading
+35 −8
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package android.view;


import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.MessageQueue;
import android.util.Log;
import android.util.Log;
@@ -25,6 +26,10 @@ import android.util.Log;
import dalvik.system.CloseGuard;
import dalvik.system.CloseGuard;


import java.lang.ref.WeakReference;
import java.lang.ref.WeakReference;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;


/**
/**
 * Provides a low-level mechanism for an application to send input events.
 * Provides a low-level mechanism for an application to send input events.
@@ -37,10 +42,10 @@ public abstract class InputEventSender {


    private long mSenderPtr;
    private long mSenderPtr;


    // We keep references to the input channel and message queue objects here so that
    // We keep references to the input channel and message queue objects (indirectly through
    // they are not GC'd while the native peer of the receiver is using them.
    // Handler) here so that they are not GC'd while the native peer of the receiver is using them.
    private InputChannel mInputChannel;
    private InputChannel mInputChannel;
    private MessageQueue mMessageQueue;
    private Handler mHandler;


    private static native long nativeInit(WeakReference<InputEventSender> sender,
    private static native long nativeInit(WeakReference<InputEventSender> sender,
            InputChannel inputChannel, MessageQueue messageQueue);
            InputChannel inputChannel, MessageQueue messageQueue);
@@ -63,9 +68,9 @@ public abstract class InputEventSender {
        }
        }


        mInputChannel = inputChannel;
        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mHandler = new Handler(looper);
        mSenderPtr = nativeInit(new WeakReference<InputEventSender>(this),
        mSenderPtr = nativeInit(new WeakReference<InputEventSender>(this),
                mInputChannel, mMessageQueue);
                mInputChannel, looper.getQueue());


        mCloseGuard.open("InputEventSender.dispose");
        mCloseGuard.open("InputEventSender.dispose");
    }
    }
@@ -98,8 +103,8 @@ public abstract class InputEventSender {
            nativeDispose(mSenderPtr);
            nativeDispose(mSenderPtr);
            mSenderPtr = 0;
            mSenderPtr = 0;
        }
        }
        mHandler = null;
        mInputChannel = null;
        mInputChannel = null;
        mMessageQueue = null;
    }
    }


    /**
    /**
@@ -122,8 +127,8 @@ public abstract class InputEventSender {
    }
    }


    /**
    /**
     * Sends an input event.
     * Sends an input event. Can be called from any thread. Do not call this if the looper thread
     * Must be called on the same Looper thread to which the sender is attached.
     * is blocked! It would cause a deadlock.
     *
     *
     * @param seq The input event sequence number.
     * @param seq The input event sequence number.
     * @param event The input event to send.
     * @param event The input event to send.
@@ -140,6 +145,28 @@ public abstract class InputEventSender {
            return false;
            return false;
        }
        }


        if (mHandler.getLooper().isCurrentThread()) {
            return sendInputEventInternal(seq, event);
        }
        // This is being called on another thread. Post a runnable to the looper thread
        // with the event injection, and wait until it's processed.
        final RunnableFuture<Boolean> task = new FutureTask<>(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                return sendInputEventInternal(seq, event);
            }
        });
        mHandler.post(task);
        try {
            return task.get();
        } catch (InterruptedException exc) {
            throw new IllegalStateException("Interrupted while sending " + event + ": " + exc);
        } catch (ExecutionException exc) {
            throw new IllegalStateException("Couldn't send " + event + ": " + exc);
        }
    }

    private boolean sendInputEventInternal(int seq, InputEvent event) {
        if (event instanceof KeyEvent) {
        if (event instanceof KeyEvent) {
            return nativeSendKeyEvent(mSenderPtr, seq, (KeyEvent)event);
            return nativeSendKeyEvent(mSenderPtr, seq, (KeyEvent)event);
        } else {
        } else {