Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69c298b0 authored by Nathalie Le Clair's avatar Nathalie Le Clair
Browse files

Terminate ARC before enabling eARC in the HAL

This is required by the eARC specification: an ARC connection and an
eARC connection cannot exist simultaneously.

The HAL can only initiate an eARC connection once the framework has
informed it with a setEarcEnabled HAL call. The framework waits until
ARC has been terminated to do this.

It's enough to terminate ARC before enabling eARC in the HAL: there is
no need to terminate it again once the HAL reports that eARC is
connected succesfully. Reason: in all situations where the eARC HAL
could report that eARC got connected, ARC has been terminated before:
1. On hotplug in: this means that there was a hotplug out before -->
   eARC is in the IDLE state --> ARC was disconnected when we entered
   the IDLE state.
2. On boot: Both ARC and eARC are disconnected before boot, and on boot,
   eARC gets attempted first.
3. On wake-up: ARC was terminated on the last standby.
4. When eARC gets enabled in the HAL: this CL explicitly terminates ARC.

Bug: 262573690
Test: atest
Change-Id: I91d20fd382c4e4e4102683ace5f2ef55a10e1048
parent c02f2fb2
Loading
Loading
Loading
Loading
+35 −10
Original line number Diff line number Diff line
@@ -393,7 +393,7 @@ public class HdmiControlService extends SystemService {
    // and the eARC HAL is present.
    @GuardedBy("mLock")
    @VisibleForTesting
    protected boolean mEarcSupported;
    private boolean mEarcSupported;

    // Set to true while the eARC feature is enabled.
    @GuardedBy("mLock")
@@ -726,7 +726,7 @@ public class HdmiControlService extends SystemService {
            if (isEarcEnabled()) {
                initializeEarc(INITIATED_BY_BOOT_UP);
            } else {
                setEarcEnabledInHal(false);
                setEarcEnabledInHal(false, false);
            }
        }

@@ -3522,7 +3522,7 @@ public class HdmiControlService extends SystemService {
                }
                initializeEarc(startReason);
            } else {
                setEarcEnabledInHal(false);
                setEarcEnabledInHal(false, false);
            }
        }
        // TODO: Initialize MHL local devices.
@@ -4418,8 +4418,17 @@ public class HdmiControlService extends SystemService {

    private void initializeEarc(int initiatedBy) {
        Slog.i(TAG, "eARC initialized, reason = " + initiatedBy);
        setEarcEnabledInHal(true);
        initializeEarcLocalDevice(initiatedBy);

        if (initiatedBy == INITIATED_BY_ENABLE_EARC) {
            // Since ARC and eARC cannot be connected simultaneously, we need to terminate ARC
            // before even enabling eARC.
            setEarcEnabledInHal(true, true);
        } else {
            // On boot, wake-up, and hotplug in, eARC will always be attempted before ARC.
            // So there is no need to explicitly terminate ARC before enabling eARC.
            setEarcEnabledInHal(true, false);
        }
    }

    @ServiceThreadOnly
@@ -4475,7 +4484,7 @@ public class HdmiControlService extends SystemService {
    @ServiceThreadOnly
    private void onDisableEarc() {
        disableEarcLocalDevice();
        setEarcEnabledInHal(false);
        setEarcEnabledInHal(false, false);
        clearEarcLocalDevice();
    }

@@ -4509,13 +4518,29 @@ public class HdmiControlService extends SystemService {

    @ServiceThreadOnly
    @VisibleForTesting
    protected void setEarcEnabledInHal(boolean enabled) {
    protected void setEarcEnabledInHal(boolean enabled, boolean terminateArcFirst) {
        assertRunOnServiceThread();
        if (terminateArcFirst) {
            startArcAction(false, new IHdmiControlCallback.Stub() {
                @Override
                public void onComplete(int result) throws RemoteException {
                    // Independently of the result (i.e. independently of whether the ARC RX device
                    // responded with <Terminate ARC> or not), we always end up terminating ARC in
                    // the HAL. As soon as we do that, we can enable eARC in the HAL.
                    mEarcController.setEarcEnabled(enabled);
                    mCecController.setHpdSignalType(
                            enabled ? Constants.HDMI_HPD_TYPE_STATUS_BIT
                                    : Constants.HDMI_HPD_TYPE_PHYSICAL,
                            mEarcPortId);
                }
            });
        } else {
            mEarcController.setEarcEnabled(enabled);
            mCecController.setHpdSignalType(
                    enabled ? Constants.HDMI_HPD_TYPE_STATUS_BIT : Constants.HDMI_HPD_TYPE_PHYSICAL,
                    mEarcPortId);
        }
    }

    @ServiceThreadOnly
    void handleEarcStateChange(int status, int portId) {
+45 −0
Original line number Diff line number Diff line
@@ -1504,4 +1504,49 @@ public class HdmiCecLocalDeviceTvTest {

        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
    }

    @Test
    public void enableEarc_terminateArc() {
        // Emulate Audio device on port 0x2000 (supports ARC and eARC)
        mNativeWrapper.setPortConnectionStatus(2, true);
        HdmiCecMessage reportPhysicalAddress =
                HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                        ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
        mNativeWrapper.onCecMessage(reportPhysicalAddress);
        mTestLooper.dispatchAll();

        HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
                ADDR_AUDIO_SYSTEM,
                ADDR_TV);

        mNativeWrapper.onCecMessage(initiateArc);
        mTestLooper.dispatchAll();

        HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
                ADDR_TV,
                ADDR_AUDIO_SYSTEM);
        // <Report ARC Initiated> should only be sent after SAD querying is done
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);

        // Finish querying SADs
        assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
        mNativeWrapper.clearResultMessages();
        mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
        mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
        mNativeWrapper.clearResultMessages();

        mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
        mTestLooper.dispatchAll();

        HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
                ADDR_TV,
                ADDR_AUDIO_SYSTEM);

        assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
    }
}
+18 −34
Original line number Diff line number Diff line
@@ -145,6 +145,7 @@ public class HdmiControlServiceTest {
        mHdmiControlServiceSpy.setPowerManager(mPowerManager);
        mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mHdmiControlServiceSpy.setAudioManager(mAudioManager);
        mHdmiControlServiceSpy.setEarcSupported(true);

        mTestLooper.dispatchAll();
    }
@@ -1089,7 +1090,6 @@ public class HdmiControlServiceTest {

    @Test
    public void disableEarc_clearEarcLocalDevice() {
        mHdmiControlServiceSpy.setEarcSupported(true);
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        mHdmiControlServiceSpy.addEarcLocalDevice(
                new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy));
@@ -1102,7 +1102,6 @@ public class HdmiControlServiceTest {

    @Test
    public void disableCec_doNotClearEarcLocalDevice() {
        mHdmiControlServiceSpy.setEarcSupported(true);
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        mHdmiControlServiceSpy.addEarcLocalDevice(
                new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy));
@@ -1115,7 +1114,6 @@ public class HdmiControlServiceTest {

    @Test
    public void enableCec_initializeCecLocalDevices() {
        mHdmiControlServiceSpy.setEarcSupported(true);
        Mockito.clearInvocations(mHdmiControlServiceSpy);
        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
        mTestLooper.dispatchAll();
@@ -1127,7 +1125,6 @@ public class HdmiControlServiceTest {

    @Test
    public void enableEarc_initializeEarcLocalDevices() {
        mHdmiControlServiceSpy.setEarcSupported(true);
        Mockito.clearInvocations(mHdmiControlServiceSpy);
        mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
        mTestLooper.dispatchAll();
@@ -1139,7 +1136,6 @@ public class HdmiControlServiceTest {

    @Test
    public void disableCec_DoNotInformHalAboutEarc() {
        mHdmiControlServiceSpy.setEarcSupported(true);
        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
@@ -1149,7 +1145,7 @@ public class HdmiControlServiceTest {
                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
        mTestLooper.dispatchAll();
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean());
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean(), anyBoolean());
    }

    @Test
@@ -1157,15 +1153,14 @@ public class HdmiControlServiceTest {
        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);
        verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false);
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean());
    }

    @Test
@@ -1173,14 +1168,13 @@ public class HdmiControlServiceTest {
        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());
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean(), anyBoolean());
    }

    @Test
@@ -1188,15 +1182,14 @@ public class HdmiControlServiceTest {
        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);
        verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, true);
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean());
    }

    @Test
@@ -1204,13 +1197,15 @@ public class HdmiControlServiceTest {
        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                HdmiControlManager.SETTING_NAME_EARC_ENABLED,
                HdmiControlManager.EARC_FEATURE_ENABLED);
        mHdmiControlServiceSpy.setEarcSupported(true);
        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
        mTestLooper.dispatchAll();
        Mockito.clearInvocations(mHdmiControlServiceSpy);
        mHdmiControlServiceSpy.initService();
        mTestLooper.dispatchAll();
        verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true);
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false);
        verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, false);
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean());
    }

    @Test
@@ -1218,13 +1213,12 @@ public class HdmiControlServiceTest {
        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);
        verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false);
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean());
    }

    @Test
@@ -1232,13 +1226,12 @@ public class HdmiControlServiceTest {
        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);
        verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, false);
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean());
    }

    @Test
@@ -1246,18 +1239,16 @@ public class HdmiControlServiceTest {
        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);
        verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false);
        verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean());
    }

    @Test
    public void earcIdle_blocksArcConnection() {
        mHdmiControlServiceSpy.mEarcSupported = true;
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
        localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_IDLE);
@@ -1267,7 +1258,6 @@ public class HdmiControlServiceTest {

    @Test
    public void earcPending_blocksArcConnection() {
        mHdmiControlServiceSpy.mEarcSupported = true;
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
        localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_PENDING);
@@ -1277,7 +1267,6 @@ public class HdmiControlServiceTest {

    @Test
    public void earcEnabled_blocksArcConnection() {
        mHdmiControlServiceSpy.mEarcSupported = true;
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
        localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_CONNECTED);
@@ -1287,7 +1276,6 @@ public class HdmiControlServiceTest {

    @Test
    public void arcPending_doesNotBlockArcConnection() {
        mHdmiControlServiceSpy.mEarcSupported = true;
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
        localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING);
@@ -1297,7 +1285,6 @@ public class HdmiControlServiceTest {

    @Test
    public void earcStatusBecomesIdle_terminateArc() {
        mHdmiControlServiceSpy.mEarcSupported = true;
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
        mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
@@ -1307,7 +1294,6 @@ public class HdmiControlServiceTest {

    @Test
    public void earcStatusBecomesEnabled_doNothing() {
        mHdmiControlServiceSpy.mEarcSupported = true;
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
        mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
@@ -1317,7 +1303,6 @@ public class HdmiControlServiceTest {

    @Test
    public void earcStatusBecomesPending_doNothing() {
        mHdmiControlServiceSpy.mEarcSupported = true;
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
        mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
@@ -1327,7 +1312,6 @@ public class HdmiControlServiceTest {

    @Test
    public void earcStatusBecomesNotEnabled_initiateArc() {
        mHdmiControlServiceSpy.mEarcSupported = true;
        mHdmiControlServiceSpy.clearEarcLocalDevice();
        HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
        mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);