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