@@ -70,11 +70,20 @@ class InputConsumerTest : public testing::Test, public InputConsumerCallbacks {
7070 []() { return std::make_unique<LegacyResampler>(); });
7171 }
7272
73- void invokeLooperCallback () const {
73+ bool invokeLooperCallback () const {
7474 sp<LooperCallback> callback;
75- ASSERT_TRUE (mLooper ->getFdStateDebug (mClientTestChannel ->getFd (), /* ident=*/ nullptr ,
76- /* events=*/ nullptr , &callback, /* data=*/ nullptr ));
75+ const bool found =
76+ mLooper ->getFdStateDebug (mClientTestChannel ->getFd (), /* ident=*/ nullptr ,
77+ /* events=*/ nullptr , &callback, /* data=*/ nullptr );
78+ if (!found) {
79+ return false ;
80+ }
81+ if (callback == nullptr ) {
82+ LOG (FATAL) << " Looper has the fd of interest, but the callback is null!" ;
83+ return false ;
84+ }
7785 callback->handleEvent (mClientTestChannel ->getFd (), ALOOPER_EVENT_INPUT, /* data=*/ nullptr );
86+ return true ;
7887 }
7988
8089 void assertOnBatchedInputEventPendingWasCalled () {
@@ -270,6 +279,27 @@ TEST_F(InputConsumerTest, UnhandledEventsNotFinishedInDestructor) {
270279 mClientTestChannel ->assertNoSentMessages ();
271280}
272281
282+ /* *
283+ * Check what happens when looper invokes callback after consumer has been destroyed.
284+ * This reproduces a crash where the LooperEventCallback was added back to the Looper during
285+ * destructor, thus allowing the looper callback to be invoked onto a null consumer object.
286+ */
287+ TEST_F (InputConsumerTest, LooperCallbackInvokedAfterConsumerDestroyed) {
288+ mClientTestChannel ->enqueueMessage (
289+ InputMessageBuilder{InputMessage::Type::MOTION, /* seq=*/ 0 }.action (ACTION_DOWN).build ());
290+ mClientTestChannel ->enqueueMessage (
291+ InputMessageBuilder{InputMessage::Type::MOTION, /* seq=*/ 1 }.action (ACTION_MOVE).build ());
292+ ASSERT_TRUE (invokeLooperCallback ());
293+ assertOnBatchedInputEventPendingWasCalled ();
294+ assertReceivedMotionEvent (WithMotionAction (ACTION_DOWN));
295+ mClientTestChannel ->assertFinishMessage (/* seq=*/ 0 , /* handled=*/ true );
296+
297+ // Now, destroy the consumer and invoke the looper callback again after it's been destroyed.
298+ mConsumer .reset ();
299+ mClientTestChannel ->assertFinishMessage (/* seq=*/ 1 , /* handled=*/ false );
300+ ASSERT_FALSE (invokeLooperCallback ());
301+ }
302+
273303/* *
274304 * Send an event to the InputConsumer, but do not invoke "consumeBatchedInputEvents", thus leaving
275305 * the input event unconsumed by the callbacks. Ensure that no crash occurs when the consumer is
0 commit comments