From 40355178f20c01a9141146bb3f828d32243f4208 Mon Sep 17 00:00:00 2001 From: Nathalie Le Clair Date: Tue, 9 Aug 2022 09:18:03 +0200 Subject: [PATCH] Enable and disable eARC in the HAL Depending on the settings value, enable or disable on boot and wakeup. Enable when the setting gets enabled. Disable when the setting gets disabled. Test: atest Bug: 240388084 Change-Id: I74a90d26e8cde0f9acfd5eb1b33c845a6a995b18 --- .../server/hdmi/HdmiCecLocalDevice.java | 2 +- .../server/hdmi/HdmiControlService.java | 68 +++++++--- .../server/hdmi/HdmiEarcLocalDevice.java | 5 +- .../android/server/hdmi/HdmiLocalDevice.java | 26 ++++ .../server/hdmi/HdmiControlServiceTest.java | 128 +++++++++++++++++- 5 files changed, 203 insertions(+), 26 deletions(-) create mode 100644 services/core/java/com/android/server/hdmi/HdmiLocalDevice.java diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index b4d7fb9d91532..689183fbbf74a 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -54,7 +54,7 @@ import java.util.concurrent.ArrayBlockingQueue; * Class that models a logical CEC device hosted in this system. Handles initialization, CEC * commands that call for actions customized per device type. */ -abstract class HdmiCecLocalDevice { +abstract class HdmiCecLocalDevice extends HdmiLocalDevice { private static final String TAG = "HdmiCecLocalDevice"; private static final int MAX_HDMI_ACTIVE_SOURCE_HISTORY = 10; diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 7f5a7c8b7aae3..45c7de9763b7a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -713,8 +713,12 @@ public class HdmiControlService extends SystemService { mEarcSupported &= (mEarcController != null); } - if (isEarcSupportedAndEnabled()) { - initializeEarc(INITIATED_BY_BOOT_UP); + if (isEarcSupported()) { + if (isEarcEnabled()) { + initializeEarc(INITIATED_BY_BOOT_UP); + } else { + setEarcEnabledInHal(false); + } } mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, @@ -3386,9 +3390,15 @@ public class HdmiControlService extends SystemService { } } - private boolean isEarcSupportedAndEnabled() { + private boolean isEarcEnabled() { synchronized (mLock) { - return mEarcSupported && mEarcEnabled; + return mEarcEnabled; + } + } + + private boolean isEarcSupported() { + synchronized (mLock) { + return mEarcSupported; } } @@ -3485,21 +3495,24 @@ public class HdmiControlService extends SystemService { } else { Slog.i(TAG, "Device does not support HDMI-CEC."); } - if (isEarcSupportedAndEnabled()) { - int startReason = -1; - switch (wakeUpAction) { - case WAKE_UP_SCREEN_ON: - startReason = INITIATED_BY_SCREEN_ON; - break; - case WAKE_UP_BOOT_UP: - startReason = INITIATED_BY_BOOT_UP; - break; - default: - Slog.e(TAG, "wakeUpAction " + wakeUpAction + " not defined."); - return; - + if (isEarcSupported()) { + if (isEarcEnabled()) { + int startReason = -1; + switch (wakeUpAction) { + case WAKE_UP_SCREEN_ON: + startReason = INITIATED_BY_SCREEN_ON; + break; + case WAKE_UP_BOOT_UP: + startReason = INITIATED_BY_BOOT_UP; + break; + default: + Slog.e(TAG, "wakeUpAction " + wakeUpAction + " not defined."); + return; + } + initializeEarc(startReason); + } else { + setEarcEnabledInHal(false); } - initializeEarc(startReason); } // TODO: Initialize MHL local devices. } @@ -4394,6 +4407,7 @@ public class HdmiControlService extends SystemService { private void initializeEarc(int initiatedBy) { Slog.i(TAG, "eARC initialized, reason = " + initiatedBy); + setEarcEnabledInHal(true); initializeEarcLocalDevice(initiatedBy); } @@ -4415,8 +4429,8 @@ public class HdmiControlService extends SystemService { synchronized (mLock) { mEarcEnabled = (enabled == EARC_FEATURE_ENABLED); - if (!mEarcSupported) { - Slog.i(TAG, "Enabled/disabled eARC setting, but the hardware doesn´t support eARC." + if (!isEarcSupported()) { + Slog.i(TAG, "Enabled/disabled eARC setting, but the hardware doesn´t support eARC. " + "This settings change doesn´t have an effect."); return; } @@ -4448,6 +4462,8 @@ public class HdmiControlService extends SystemService { @ServiceThreadOnly private void onDisableEarc() { + disableEarcLocalDevice(); + setEarcEnabledInHal(false); clearEarcLocalDevice(); } @@ -4471,5 +4487,17 @@ public class HdmiControlService extends SystemService { assertRunOnServiceThread(); return mEarcLocalDevice; } + private void disableEarcLocalDevice() { + if (mEarcLocalDevice == null) { + return; + } + mEarcLocalDevice.disableDevice(); + } + @ServiceThreadOnly + @VisibleForTesting + protected void setEarcEnabledInHal(boolean enabled) { + assertRunOnServiceThread(); + mEarcController.setEarcEnabled(enabled); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java index 1e9d338fc2d68..720dff5e77adb 100644 --- a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java @@ -22,9 +22,12 @@ import android.util.IndentingPrintWriter; * Class that models a local eARC device hosted in this system. * The class contains methods that are common between eARC TX and eARC RX devices. */ -public class HdmiEarcLocalDevice { +public class HdmiEarcLocalDevice extends HdmiLocalDevice { private static final String TAG = "HdmiEarcLocalDevice"; + protected void disableDevice() { + } + /** Dump internal status of HdmiEarcLocalDevice object */ protected void dump(final IndentingPrintWriter pw) { // Should be overridden in the more specific classes diff --git a/services/core/java/com/android/server/hdmi/HdmiLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiLocalDevice.java new file mode 100644 index 0000000000000..96fb28c5321ca --- /dev/null +++ b/services/core/java/com/android/server/hdmi/HdmiLocalDevice.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +/** + * Class that models an HDMI device hosted in this system. + * Can be used to share methods between CEC and eARC local devices. + * Currently just a placeholder. + */ +abstract class HdmiLocalDevice { + private static final String TAG = "HdmiLocalDevice"; +} 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 f07ee6c2be4e7..ff873faf02b7d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -22,6 +22,7 @@ import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV; import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; +import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON; import static com.google.common.truth.Truth.assertThat; @@ -29,6 +30,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; @@ -128,13 +130,13 @@ public class HdmiControlServiceTest { mLocalDevices.add(mPlaybackDeviceSpy); mHdmiPortInfo = new HdmiPortInfo[4]; mHdmiPortInfo[0] = - new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false); + new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false, false); mHdmiPortInfo[1] = - new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false); + new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false, false); mHdmiPortInfo[2] = - new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, false); + new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true, true); mHdmiPortInfo[3] = - new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false); + new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false, false); mNativeWrapper.setPortInfo(mHdmiPortInfo); mHdmiControlServiceSpy.initService(); mPowerManager = new FakePowerManagerWrapper(mContextSpy); @@ -1131,6 +1133,124 @@ public class HdmiControlServiceTest { verify(mHdmiControlServiceSpy, times(1)).initializeEarcLocalDevice(anyInt()); } + @Test + public void disableCec_DoNotInformHalAboutEarc() { + mHdmiControlServiceSpy.setEarcSupported(true); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean()); + } + + @Test + public void disableEarc_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_ENABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_DISABLED); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + } + + @Test + public void enableCec_DoNotInformHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean()); + } + + @Test + public void enableEarc_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_DISABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + } + + @Test + public void bootWithEarcEnabled_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_ENABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.initService(); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + } + + @Test + public void bootWithEarcDisabled_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_DISABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.initService(); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + } + + @Test + public void wakeUpWithEarcEnabled_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_ENABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + } + + @Test + public void wakeUpWithEarcDisabled_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_DISABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + } + protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback { private boolean mCanGoToStandby;