• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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