1 /*
<lambda>null2 * 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
getTestKeyEventnull44 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) {
onInputEventnull51 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
setUpnull69 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
tearDownnull79 fun tearDown() {
80 mHandlerThread.quitSafely()
81 }
82
83 @Test
testSendAndReceiveKeynull84 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
testSendAndReceiveTimelinenull100 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
testSendAndReceiveInvalidTimelinenull112 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
testCrashingReceiverDoesNotCrashnull133 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