From 652248646d0212dc53f376ff5e34aa599a214643 Mon Sep 17 00:00:00 2001 From: Paul Colta Date: Thu, 14 Dec 2023 15:54:38 +0100 Subject: HDMI: Avoid NPE on Hotplug In In b/278002479#comment109, we discussed with MTK about a NullPointerException (NPE) that occurs when there are two consecutive Hotplugs (In & Out). This leads to an unsynchronized physical address between the HAL and framework, which results in the framework receiving an invalid physical address for the hotplug in. Bug: 316343326 Bug: 278002479 Test: atest HdmiControlServiceTest Change-Id: I16db00396e0f677e383c343515cb3338374bb9c2 --- .../com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java | 3 ++- .../java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java | 3 ++- .../core/java/com/android/server/hdmi/HdmiControlService.java | 3 ++- .../src/com/android/server/hdmi/HdmiControlServiceTest.java | 9 +++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index b3aa351d69d7..70993ca3e21b 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -201,7 +201,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { if (WAKE_ON_HOTPLUG && connected) { mService.wakeUp(); } - if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) { + HdmiPortInfo portInfo = mService.getPortInfo(portId); + if (portInfo != null && portInfo.getType() == HdmiPortInfo.PORT_OUTPUT) { mCecMessageCache.flushAll(); if (!connected) { if (isSystemAudioActivated()) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java index 7e8a2cc6d835..29303aab6fa9 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java @@ -92,7 +92,8 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { @ServiceThreadOnly void onHotplug(int portId, boolean connected) { assertRunOnServiceThread(); - if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) { + HdmiPortInfo portInfo = mService.getPortInfo(portId); + if (portInfo != null && portInfo.getType() == HdmiPortInfo.PORT_OUTPUT) { mCecMessageCache.flushAll(); } // We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3. diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index b3926fd1b5ba..92537064f766 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -1783,8 +1783,9 @@ public class HdmiControlService extends SystemService { // initPortInfo at hotplug event. mHdmiCecNetwork.initPortInfo(); + HdmiPortInfo portInfo = getPortInfo(portId); if (connected && !isTvDevice() - && getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) { + && portInfo != null && portInfo.getType() == HdmiPortInfo.PORT_OUTPUT) { ArrayList localDevices = new ArrayList<>(); for (int type : getCecLocalDeviceTypes()) { HdmiCecLocalDevice localDevice = mHdmiCecNetwork.getLocalDevice(type); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 708ee352a8c9..99fa30c588db 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -1706,6 +1706,15 @@ public class HdmiControlServiceTest { verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(false), any()); } + @Test + public void onHotplugIn_invalidPortId_noAddressAllocation() { + mHdmiControlServiceSpy.onHotplug(-1, true); + mTestLooper.dispatchAll(); + + verify(mHdmiControlServiceSpy, times(0)) + .allocateLogicalAddress(any(), eq(INITIATED_BY_HOTPLUG)); + } + protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback { private boolean mCanGoToStandby; -- cgit v1.2.3-59-g8ed1b