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

Commit ad7b8ebe authored by Nathalie Le Clair's avatar Nathalie Le Clair Committed by Android (Google) Code Review
Browse files

Merge changes I8514bcc0,I91d20fd3,Iefc324ba,I29676ef7,I5c3d172f

* changes:
  Terminate ARC when eARC gets enabled on the RX device
  Terminate ARC before enabling eARC in the HAL
  Update ARC state based on eARC status updates
  Add callback to startArcAction
  Block new ARC connections during eARC connection
parents e856e73b ffa600a0
Loading
Loading
Loading
Loading
+40 −11
Original line number Diff line number Diff line
@@ -899,10 +899,16 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {

    @ServiceThreadOnly
    void startArcAction(boolean enabled) {
        startArcAction(enabled, null);
    }

    @ServiceThreadOnly
    void startArcAction(boolean enabled, IHdmiControlCallback callback) {
        assertRunOnServiceThread();
        HdmiDeviceInfo info = getAvrDeviceInfo();
        if (info == null) {
            Slog.w(TAG, "Failed to start arc action; No AVR device.");
            invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
            return;
        }
        if (!canStartArcUpdateAction(info.getLogicalAddress(), enabled)) {
@@ -910,19 +916,37 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            if (enabled && !isConnectedToArcPort(info.getPhysicalAddress())) {
                displayOsd(OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT);
            }
            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
            return;
        }
        if (enabled && mService.earcBlocksArcConnection()) {
            Slog.i(TAG,
                    "ARC connection blocked because eARC connection is established or being "
                            + "established.");
            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
            return;
        }

        // Terminate opposite action and start action if not exist.
        // Terminate opposite action and create an action with callback.
        if (enabled) {
            removeAction(RequestArcTerminationAction.class);
            if (!hasAction(RequestArcInitiationAction.class)) {
                addAndStartAction(new RequestArcInitiationAction(this, info.getLogicalAddress()));
            if (hasAction(RequestArcInitiationAction.class)) {
                RequestArcInitiationAction existingInitiationAction =
                        getActions(RequestArcInitiationAction.class).get(0);
                existingInitiationAction.addCallback(callback);
            } else {
                addAndStartAction(
                        new RequestArcInitiationAction(this, info.getLogicalAddress(), callback));
            }
        } else {
            removeAction(RequestArcInitiationAction.class);
            if (!hasAction(RequestArcTerminationAction.class)) {
                addAndStartAction(new RequestArcTerminationAction(this, info.getLogicalAddress()));
            if (hasAction(RequestArcTerminationAction.class)) {
                RequestArcTerminationAction existingTerminationAction =
                        getActions(RequestArcTerminationAction.class).get(0);
                existingTerminationAction.addCallback(callback);
            } else {
                addAndStartAction(
                        new RequestArcTerminationAction(this, info.getLogicalAddress(), callback));
            }
        }
    }
@@ -1010,6 +1034,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    protected int handleInitiateArc(HdmiCecMessage message) {
        assertRunOnServiceThread();

        if (mService.earcBlocksArcConnection()) {
            Slog.i(TAG,
                    "ARC connection blocked because eARC connection is established or being "
                            + "established.");
            return Constants.ABORT_NOT_IN_CORRECT_MODE;
        }

        if (!canStartArcUpdateAction(message.getSource(), true)) {
            HdmiDeviceInfo avrDeviceInfo = getAvrDeviceInfo();
            if (avrDeviceInfo == null) {
@@ -1023,9 +1054,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            return Constants.ABORT_REFUSED;
        }

        // In case where <Initiate Arc> is started by <Request ARC Initiation>
        // need to clean up RequestArcInitiationAction.
        removeAction(RequestArcInitiationAction.class);
        // In case where <Initiate Arc> is started by <Request ARC Initiation>, this message is
        // handled in RequestArcInitiationAction as well.
        SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
                message.getSource(), true);
        addAndStartAction(action);
@@ -1059,9 +1089,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            return Constants.HANDLED;
        }
        // Do not check ARC configuration since the AVR might have been already removed.
        // Clean up RequestArcTerminationAction in case <Terminate Arc> was started by
        // <Request ARC Termination>.
        removeAction(RequestArcTerminationAction.class);
        // In case where <Terminate Arc> is started by <Request ARC Termination>, this
        // message is handled in RequestArcTerminationAction as well.
        SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
                message.getSource(), false);
        addAndStartAction(action);
+57 −10
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_ENABLED;
import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
import static com.android.server.hdmi.Constants.DISABLED;
import static com.android.server.hdmi.Constants.ENABLED;
import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING;
import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
@@ -392,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")
@@ -725,7 +726,7 @@ public class HdmiControlService extends SystemService {
            if (isEarcEnabled()) {
                initializeEarc(INITIATED_BY_BOOT_UP);
            } else {
                setEarcEnabledInHal(false);
                setEarcEnabledInHal(false, false);
            }
        }

@@ -3236,6 +3237,9 @@ public class HdmiControlService extends SystemService {
    }

    private void invokeCallback(IHdmiControlCallback callback, int result) {
        if (callback == null) {
            return;
        }
        try {
            callback.onComplete(result);
        } catch (RemoteException e) {
@@ -3518,7 +3522,7 @@ public class HdmiControlService extends SystemService {
                }
                initializeEarc(startReason);
            } else {
                setEarcEnabledInHal(false);
                setEarcEnabledInHal(false, false);
            }
        }
        // TODO: Initialize MHL local devices.
@@ -4414,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
@@ -4464,13 +4477,14 @@ public class HdmiControlService extends SystemService {

    @ServiceThreadOnly
    private void onEnableEarc() {
        // This will terminate ARC as well.
        initializeEarc(INITIATED_BY_ENABLE_EARC);
    }

    @ServiceThreadOnly
    private void onDisableEarc() {
        disableEarcLocalDevice();
        setEarcEnabledInHal(false);
        setEarcEnabledInHal(false, false);
        clearEarcLocalDevice();
    }

@@ -4504,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) {
@@ -4540,4 +4570,21 @@ public class HdmiControlService extends SystemService {
            mEarcLocalDevice.handleEarcCapabilitiesReported(rawCapabilities);
        }
    }

    protected boolean earcBlocksArcConnection() {
        if (mEarcLocalDevice == null) {
            return false;
        }
        synchronized (mLock) {
            return mEarcLocalDevice.mEarcStatus != HDMI_EARC_STATUS_ARC_PENDING;
        }
    }

    protected void startArcAction(boolean enabled, IHdmiControlCallback callback) {
        if (!isTvDeviceEnabled()) {
            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
        } else {
            tv().startArcAction(enabled, callback);
        }
    }
}
+14 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.hdmi;

import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING;
import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_CONNECTED;
import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_PENDING;
import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_IDLE;

import android.hardware.hdmi.HdmiDeviceInfo;
@@ -69,23 +70,36 @@ public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice {
    HdmiEarcLocalDeviceTx(HdmiControlService service) {
        super(service, HdmiDeviceInfo.DEVICE_TV);

        synchronized (mLock) {
            mEarcStatus = HDMI_EARC_STATUS_EARC_PENDING;
        }
        mReportCapsHandler = new Handler(service.getServiceLooper());
        mReportCapsRunnable = new ReportCapsRunnable();
    }

    protected void handleEarcStateChange(@Constants.EarcStatus int status) {
        int oldEarcStatus;
        synchronized (mLock) {
            HdmiLogger.debug(TAG, "eARC state change [old:%b new %b]", mEarcStatus,
                    status);
            oldEarcStatus = mEarcStatus;
            mEarcStatus = status;
        }

        mReportCapsHandler.removeCallbacksAndMessages(null);
        if (status == HDMI_EARC_STATUS_IDLE) {
            notifyEarcStatusToAudioService(false, new ArrayList<>());
            mService.startArcAction(false, null);
        } else if (status == HDMI_EARC_STATUS_ARC_PENDING) {
            notifyEarcStatusToAudioService(false, new ArrayList<>());
            mService.startArcAction(true, null);
        } else if (status == HDMI_EARC_STATUS_EARC_PENDING
                && oldEarcStatus == HDMI_EARC_STATUS_ARC_PENDING) {
            mService.startArcAction(false, null);
        } else if (status == HDMI_EARC_STATUS_EARC_CONNECTED) {
            if (oldEarcStatus == HDMI_EARC_STATUS_ARC_PENDING) {
                mService.startArcAction(false, null);
            }
            mReportCapsHandler.postDelayed(mReportCapsRunnable, REPORT_CAPS_MAX_DELAY_MS);
        }
    }
+8 −28
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@

package com.android.server.hdmi;

import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.IHdmiControlCallback;

/**
 * Base feature action class for &lt;Request ARC Initiation&gt;/&lt;Request ARC Termination&gt;.
@@ -35,41 +37,19 @@ abstract class RequestArcAction extends HdmiCecFeatureAction {
     *
     * @param source {@link HdmiCecLocalDevice} instance
     * @param avrAddress address of AV receiver. It should be AUDIO_SYSTEM type
     * @param callback callback to inform about the status of the action
     * @throws IllegalArgumentException if device type of sourceAddress and avrAddress
     *                      is invalid
     */
    RequestArcAction(HdmiCecLocalDevice source, int avrAddress) {
        super(source);
    RequestArcAction(HdmiCecLocalDevice source, int avrAddress, IHdmiControlCallback callback) {
        super(source, callback);
        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV);
        HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
        mAvrAddress = avrAddress;
    }

    @Override
    boolean processCommand(HdmiCecMessage cmd) {
        if (mState != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE
                || !HdmiUtils.checkCommandSource(cmd, mAvrAddress, TAG)) {
            return false;
        }
        int opcode = cmd.getOpcode();
        switch (opcode) {
            // Handles only <Feature Abort> here and, both <Initiate ARC> and <Terminate ARC>
            // are handled in HdmiControlService itself because both can be
            // received without <Request ARC Initiation> or <Request ARC Termination>.
            case Constants.MESSAGE_FEATURE_ABORT:
                int originalOpcode = cmd.getParams()[0] & 0xFF;
                if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_TERMINATION) {
                    disableArcTransmission();
                    finish();
                    return true;
                } else if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_INITIATION) {
                    tv().disableArc();
                    finish();
                    return true;
                }
                return false;
        }
        return false;
    RequestArcAction(HdmiCecLocalDevice source, int avrAddress) {
        this(source, avrAddress, null);
    }

    protected final void disableArcTransmission() {
@@ -86,6 +66,6 @@ abstract class RequestArcAction extends HdmiCecFeatureAction {
        }
        HdmiLogger.debug("[T] RequestArcAction.");
        disableArcTransmission();
        finish();
        finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
    }
}
+37 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.hdmi;

import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.tv.cec.V1_0.SendMessageResult;

/**
@@ -35,6 +37,16 @@ final class RequestArcInitiationAction extends RequestArcAction {
        super(source, avrAddress);
    }

    /**
     * @Constructor
     *
     * For more details look at {@link RequestArcAction#RequestArcAction}.
     */
    RequestArcInitiationAction(HdmiCecLocalDevice source, int avrAddress,
            IHdmiControlCallback callback) {
        super(source, avrAddress, callback);
    }

    @Override
    boolean start() {
        // Seq #38
@@ -49,10 +61,34 @@ final class RequestArcInitiationAction extends RequestArcAction {
                if (error != SendMessageResult.SUCCESS) {
                    // Turn off ARC status if <Request ARC Initiation> fails.
                    tv().disableArc();
                    finish();
                    finishWithCallback(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
                }
            }
        });
        return true;
    }

    @Override
    boolean processCommand(HdmiCecMessage cmd) {
        if (mState != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE
                || !HdmiUtils.checkCommandSource(cmd, mAvrAddress, TAG)) {
            return false;
        }
        int opcode = cmd.getOpcode();
        switch (opcode) {
            case Constants.MESSAGE_FEATURE_ABORT:
                int originalOpcode = cmd.getParams()[0] & 0xFF;
                if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_INITIATION) {
                    tv().disableArc();
                    finishWithCallback(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
                    return true;
                }
                return false;
            case Constants.MESSAGE_INITIATE_ARC:
                finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
                // This message still needs to be handled in HdmiCecLocalDeviceTv as well.
                return false;
        }
        return false;
    }
}
Loading