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 mSender.assertNoEvents()
117 // Sender will no longer receive callbacks for this fd, even if receiver sends a valid
118 // timeline later
119 mReceiver.reportTimeline(2 /*inputEventId*/, 3 /*gpuCompletedTime*/, 4 /*presentTime*/)
120 mSender.assertNoEvents()
121 }
122
123 /**
124 * If a receiver throws an exception during 'onInputEvent' execution, the 'finally' block still
125 * completes, and therefore, finishInputEvent is called. Make sure that there's no crash in the
126 * native layer in these circumstances.
127 * In this test, we are reusing the 'mHandlerThread', but we are creating new sender and
128 * receiver.
129 */
130 @Test
testCrashingReceiverDoesNotCrashnull131 fun testCrashingReceiverDoesNotCrash() {
132 val channels = InputChannel.openInputChannelPair("TestChannel2")
133 val sender = SpyInputEventSender(channels[0], mHandlerThread.getLooper())
134
135 // Need a separate thread for the receiver so that the sender can still get the response
136 // after the receiver crashes
137 val receiverThread = HandlerThread("Receive input events")
138 receiverThread.start()
139 val crashingReceiver = CrashingInputEventReceiver(channels[1], receiverThread.getLooper())
140 receiverThread.setUncaughtExceptionHandler { thread, exception ->
141 if (thread == receiverThread && exception is IllegalArgumentException) {
142 // do nothing - this is the exception that we need to ignore
143 } else {
144 throw exception
145 }
146 }
147
148 val key = getTestKeyEvent()
149 val seq = 11
150 sender.sendInputEvent(seq, key)
151 val finishedSignal = sender.getFinishedSignal()
152 assertEquals(SpyInputEventSender.FinishedSignal(seq, handled = true), finishedSignal)
153
154 // Clean up
155 crashingReceiver.dispose()
156 sender.dispose()
157 receiverThread.quitSafely()
158 }
159 }
160