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

Commit 6aae6528 authored by Yuncheol Heo's avatar Yuncheol Heo
Browse files

Refactor <Feature Abort> logic to concentrate it in one place.

- Don't reply from the unregistered address.
- Use "unrecognized opcode" as the default reason.

Bug: 16799466, Bug: 16798785
Change-Id: I7c2ece6436f7ebd59986d2baf4f45cd86e6622d9
parent f128dbf0
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -502,24 +502,30 @@ final class HdmiCecController {
    @ServiceThreadOnly
    private void onReceiveCommand(HdmiCecMessage message) {
        assertRunOnServiceThread();
        if (isAcceptableAddress(message.getDestination())
                && mService.handleCecCommand(message)) {
        if (isAcceptableAddress(message.getDestination()) && mService.handleCecCommand(message)) {
            return;
        }
        if (message.getDestination() == Constants.ADDR_BROADCAST) {
        // Not handled message, so we will reply it with <Feature Abort>.
        maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
    }

    @ServiceThreadOnly
    void maySendFeatureAbortCommand(HdmiCecMessage message, int reason) {
        assertRunOnServiceThread();
        // Swap the source and the destination.
        int src = message.getDestination();
        int dest = message.getSource();
        if (src == Constants.ADDR_BROADCAST || dest == Constants.ADDR_UNREGISTERED) {
            // Don't reply <Feature Abort> from the unregistered devices or for the broadcasted
            // messages. See CEC 12.2 Protocol General Rules for detail.
            return;
        }
        if (message.getOpcode() == Constants.MESSAGE_FEATURE_ABORT) {
            Slog.v(TAG, "Unhandled <Feature Abort> message:" + message);
        int originalOpcode = message.getOpcode();
        if (originalOpcode == Constants.MESSAGE_FEATURE_ABORT) {
            return;
        }

        int sourceAddress = message.getDestination();
        // Reply <Feature Abort> to initiator (source) for all requests.
        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand(
                sourceAddress, message.getSource(), message.getOpcode(),
                Constants.ABORT_REFUSED);
        sendCommand(cecMessage);
        sendCommand(
                HdmiCecMessageBuilder.buildFeatureAbortCommand(src, dest, originalOpcode, reason));
    }

    @ServiceThreadOnly
+4 −10
Original line number Diff line number Diff line
@@ -308,11 +308,8 @@ abstract class HdmiCecLocalDevice {
    protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
        assertRunOnServiceThread();
        Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
        mService.sendCecCommand(
                HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
                        message.getSource(), Constants.MESSAGE_GET_MENU_LANGUAGE,
                        Constants.ABORT_UNRECOGNIZED_OPCODE));
        return true;
        // 'return false' will cause to reply with <Feature Abort>.
        return false;
    }

    @ServiceThreadOnly
@@ -431,9 +428,7 @@ abstract class HdmiCecLocalDevice {
        } else if (message.getDestination() != Constants.ADDR_BROADCAST &&
                message.getSource() != Constants.ADDR_UNREGISTERED) {
            Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>");
            mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
                    message.getSource(), Constants.MESSAGE_VENDOR_COMMAND_WITH_ID,
                    Constants.ABORT_UNRECOGNIZED_OPCODE));
            mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
        } else {
            Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
        }
@@ -448,8 +443,7 @@ abstract class HdmiCecLocalDevice {
    protected boolean handleRecordTvScreen(HdmiCecMessage message) {
        // The default behavior of <Record TV Screen> is replying <Feature Abort> with
        // "Cannot provide source".
        mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
                message.getSource(), message.getOpcode(), Constants.ABORT_CANNOT_PROVIDE_SOURCE));
        mService.maySendFeatureAbortCommand(message, Constants.ABORT_CANNOT_PROVIDE_SOURCE);
        return true;
    }

+1 −10
Original line number Diff line number Diff line
@@ -48,16 +48,7 @@ public final class HdmiCecStandbyModeHandler {
        }
        @Override
        public boolean handle(HdmiCecMessage message) {
            int src = message.getSource();
            int dest = message.getDestination();
            if (src == Constants.ADDR_BROADCAST || dest == Constants.ADDR_BROADCAST) {
                // Do not send <Feature Abort> on the message from the unassigned device
                // or the broadcasted message.
                return true;
            }
            HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand(
                    dest, src, message.getOpcode(), mReason);
            mService.sendCecCommand(cecMessage);
            mService.maySendFeatureAbortCommand(message, mReason);
            return true;
        }
    }
+12 −0
Original line number Diff line number Diff line
@@ -532,6 +532,18 @@ public final class HdmiControlService extends SystemService {
        mCecController.sendCommand(command, null);
    }

    /**
     * Send <Feature Abort> command on the given CEC message if possible.
     * If the aborted message is invalid, then it wont send the message.
     * @param command original command to be aborted
     * @param reason reason of feature abort
     */
    @ServiceThreadOnly
    void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) {
        assertRunOnServiceThread();
        mCecController.maySendFeatureAbortCommand(command, reason);
    }

    @ServiceThreadOnly
    boolean handleCecCommand(HdmiCecMessage message) {
        assertRunOnServiceThread();