1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.test.input 18 19 import android.os.HandlerThread 20 import android.os.Looper 21 import android.view.InputChannel 22 import android.view.InputEvent 23 import android.view.InputEventReceiver 24 import android.view.KeyEvent 25 import org.junit.Assert.assertEquals 26 import org.junit.After 27 import org.junit.Before 28 import org.junit.Test 29 30 private fun assertKeyEvent(expected: KeyEvent, received: KeyEvent) { 31 assertEquals(expected.action, received.action) 32 assertEquals(expected.deviceId, received.deviceId) 33 assertEquals(expected.downTime, received.downTime) 34 assertEquals(expected.eventTime, received.eventTime) 35 assertEquals(expected.keyCode, received.keyCode) 36 assertEquals(expected.scanCode, received.scanCode) 37 assertEquals(expected.repeatCount, received.repeatCount) 38 assertEquals(expected.metaState, received.metaState) 39 assertEquals(expected.flags, received.flags) 40 assertEquals(expected.source, received.source) 41 assertEquals(expected.displayId, received.displayId) 42 } 43 44 private fun getTestKeyEvent(): KeyEvent { 45 return KeyEvent(1 /*downTime*/, 1 /*eventTime*/, KeyEvent.ACTION_DOWN, 46 KeyEvent.KEYCODE_A, 0 /*repeat*/) 47 } 48 49 private class CrashingInputEventReceiver(channel: InputChannel, looper: Looper) : 50 InputEventReceiver(channel, looper) { 51 override fun onInputEvent(event: InputEvent) { 52 try { 53 throw IllegalArgumentException("This receiver crashes when it receives input event") 54 } finally { 55 finishInputEvent(event, true /*handled*/) 56 } 57 } 58 } 59 60 class InputEventSenderAndReceiverTest { 61 companion object { 62 private const val TAG = "InputEventSenderAndReceiverTest" 63 } 64 private val mHandlerThread = HandlerThread("Process input events") 65 private lateinit var mReceiver: SpyInputEventReceiver 66 private lateinit var mSender: SpyInputEventSender 67 68 @Before 69 fun setUp() { 70 val channels = InputChannel.openInputChannelPair("TestChannel") 71 mHandlerThread.start() 72 73 val looper = mHandlerThread.getLooper() 74 mSender = SpyInputEventSender(channels[0], looper) 75 mReceiver = SpyInputEventReceiver(channels[1], looper) 76 } 77 78 @After 79 fun tearDown() { 80 mHandlerThread.quitSafely() 81 } 82 83 @Test 84 fun testSendAndReceiveKey() { 85 val key = getTestKeyEvent() 86 val seq = 10 87 mSender.sendInputEvent(seq, key) 88 val receivedKey = mReceiver.getInputEvent() as KeyEvent 89 val finishedSignal = mSender.getFinishedSignal() 90 91 // Check receiver 92 assertKeyEvent(key, receivedKey) 93 94 // Check sender 95 assertEquals(SpyInputEventSender.FinishedSignal(seq, handled = true), finishedSignal) 96 } 97 98 // The timeline case is slightly unusual because it goes from InputConsumer to InputPublisher. 99 @Test 100 fun testSendAndReceiveTimeline() { 101 val sent = SpyInputEventSender.Timeline( 102 inputEventId = 1, gpuCompletedTime = 2, presentTime = 3) 103 mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime) 104 val received = mSender.getTimeline() 105 assertEquals(sent, received) 106 } 107 108 // If an invalid timeline is sent, the channel should get closed. This helps surface any 109 // app-originating bugs early, and forces the work-around to happen in the early stages of the 110 // event processing. 111 @Test 112 fun testSendAndReceiveInvalidTimeline() { 113 val sent = SpyInputEventSender.Timeline( 114 inputEventId = 1, gpuCompletedTime = 3, presentTime = 2) 115 mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime) 116 val received = mSender.getTimeline() 117 assertEquals(null, received) 118 // Sender will no longer receive callbacks for this fd, even if receiver sends a valid 119 // timeline later 120 mReceiver.reportTimeline(2 /*inputEventId*/, 3 /*gpuCompletedTime*/, 4 /*presentTime*/) 121 val receivedSecondTimeline = mSender.getTimeline() 122 assertEquals(null, receivedSecondTimeline) 123 } 124 125 /** 126 * If a receiver throws an exception during 'onInputEvent' execution, the 'finally' block still 127 * completes, and therefore, finishInputEvent is called. Make sure that there's no crash in the 128 * native layer in these circumstances. 129 * In this test, we are reusing the 'mHandlerThread', but we are creating new sender and 130 * receiver. 131 */ 132 @Test 133 fun testCrashingReceiverDoesNotCrash() { 134 val channels = InputChannel.openInputChannelPair("TestChannel2") 135 val sender = SpyInputEventSender(channels[0], mHandlerThread.getLooper()) 136 137 // Need a separate thread for the receiver so that the sender can still get the response 138 // after the receiver crashes 139 val receiverThread = HandlerThread("Receive input events") 140 receiverThread.start() 141 val crashingReceiver = CrashingInputEventReceiver(channels[1], receiverThread.getLooper()) 142 receiverThread.setUncaughtExceptionHandler { thread, exception -> 143 if (thread == receiverThread && exception is IllegalArgumentException) { 144 // do nothing - this is the exception that we need to ignore 145 } else { 146 throw exception 147 } 148 } 149 150 val key = getTestKeyEvent() 151 val seq = 11 152 sender.sendInputEvent(seq, key) 153 val finishedSignal = sender.getFinishedSignal() 154 assertEquals(SpyInputEventSender.FinishedSignal(seq, handled = true), finishedSignal) 155 156 // Clean up 157 crashingReceiver.dispose() 158 sender.dispose() 159 receiverThread.quitSafely() 160 } 161 } 162