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

Commit 3b22f349 authored by Jim Blackler's avatar Jim Blackler Committed by Android (Google) Code Review
Browse files

Merge "Revert "Implement initial statsd atoms for HDMI-CEC""

parents 8f4f0d7e 551789d1
Loading
Loading
Loading
Loading
+0 −192
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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;

import android.stats.hdmi.HdmiStatsEnums;

import com.android.internal.util.FrameworkStatsLog;

class HdmiCecAtomWriter {

    private static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100;
    private static final int ERROR_CODE_UNKNOWN = -1;

    /**
     * Writes a HdmiCecMessageReported atom representing an HDMI CEC message.
     * Should only be directly used for sent messages; for received messages,
     * use the overloaded version with the errorCode argument omitted.
     *
     * @param message      The HDMI CEC message
     * @param direction    Whether the message is incoming, outgoing, or neither
     * @param errorCode    The error code from the final attempt to send the message
     */
    public void messageReported(HdmiCecMessage message, int direction, int errorCode) {
        MessageReportedGenericArgs genericArgs = createMessageReportedGenericArgs(
                message, direction, errorCode);
        MessageReportedSpecialArgs specialArgs = createMessageReportedSpecialArgs(message);
        messageReportedBase(genericArgs, specialArgs);
    }

    /**
     * Version of messageReported for received messages, where no error code is present.
     *
     * @param message      The HDMI CEC message
     * @param direction    Whether the message is incoming, outgoing, or neither
     */
    public void messageReported(HdmiCecMessage message, int direction) {
        messageReported(message, direction, ERROR_CODE_UNKNOWN);
    }

    /**
     * Constructs the generic arguments for logging a HDMI CEC message.
     *
     * @param message      The HDMI CEC message
     * @param direction    Whether the message is incoming, outgoing, or neither
     * @param errorCode    The error code of the message if it's outgoing;
     *                     otherwise, ERROR_CODE_UNKNOWN
     */
    private MessageReportedGenericArgs createMessageReportedGenericArgs(
            HdmiCecMessage message, int direction, int errorCode) {
        int sendMessageResult = errorCode == ERROR_CODE_UNKNOWN
                ? HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN
                : errorCode + 10;
        return new MessageReportedGenericArgs(direction, message.getSource(),
                message.getDestination(), message.getOpcode(), sendMessageResult);
    }

    /**
     * Constructs the special arguments for logging an HDMI CEC message.
     *
     * @param message The HDMI CEC message to log
     * @return An object containing the special arguments for the message
     */
    private MessageReportedSpecialArgs createMessageReportedSpecialArgs(HdmiCecMessage message) {
        // Special arguments depend on message opcode
        switch (message.getOpcode()) {
            case Constants.MESSAGE_USER_CONTROL_PRESSED:
                return createUserControlPressedSpecialArgs(message);
            case Constants.MESSAGE_FEATURE_ABORT:
                return createFeatureAbortSpecialArgs(message);
            default:
                return new MessageReportedSpecialArgs();
        }
    }

    /**
     * Constructs the special arguments for a <User Control Pressed> message.
     *
     * @param message The HDMI CEC message to log
     */
    private MessageReportedSpecialArgs createUserControlPressedSpecialArgs(
            HdmiCecMessage message) {
        MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();

        int keycode = message.getParams()[0];
        if (keycode >= 0x1E && keycode <= 0x29) {
            specialArgs.mUserControlPressedCommand = HdmiStatsEnums.NUMBER;
        } else {
            specialArgs.mUserControlPressedCommand = keycode + 0x100;
        }

        return specialArgs;
    }

    /**
     * Constructs method for constructing the special arguments for a <Feature Abort> message.
     *
     * @param message The HDMI CEC message to log
     */
    private MessageReportedSpecialArgs createFeatureAbortSpecialArgs(HdmiCecMessage message) {
        MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();

        specialArgs.mFeatureAbortOpcode = message.getParams()[0] & 0xFF; // Unsigned byte
        specialArgs.mFeatureAbortReason = message.getParams()[1] + 10;

        return specialArgs;
    }

    /**
     * Writes a HdmiCecMessageReported atom.
     *
     * @param genericArgs Generic arguments; shared by all HdmiCecMessageReported atoms
     * @param specialArgs Special arguments; depends on the opcode of the message
     */
    private void messageReportedBase(MessageReportedGenericArgs genericArgs,
            MessageReportedSpecialArgs specialArgs) {
        FrameworkStatsLog.write(
                FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED,
                0, // Placeholder field
                genericArgs.mDirection,
                genericArgs.mInitiatorLogicalAddress,
                genericArgs.mDestinationLogicalAddress,
                genericArgs.mOpcode,
                genericArgs.mSendMessageResult,
                specialArgs.mUserControlPressedCommand,
                specialArgs.mFeatureAbortOpcode,
                specialArgs.mFeatureAbortReason);
    }


    /**
     * Writes a HdmiCecActiveSourceChanged atom representing a change in the active source.
     *
     * @param logicalAddress             The Logical Address of the new active source
     * @param physicalAddress            The Physical Address of the new active source
     * @param relationshipToActiveSource The relationship between this device and the active source
     */
    public void activeSourceChanged(int logicalAddress, int physicalAddress,
            @Constants.PathRelationship int relationshipToActiveSource) {
        FrameworkStatsLog.write(
                FrameworkStatsLog.HDMI_CEC_ACTIVE_SOURCE_CHANGED,
                logicalAddress,
                physicalAddress,
                relationshipToActiveSource
        );
    }

    /**
     * Contains the required arguments for creating any HdmiCecMessageReported atom
     */
    private class MessageReportedGenericArgs {
        final int mDirection;
        final int mInitiatorLogicalAddress;
        final int mDestinationLogicalAddress;
        final int mOpcode;
        final int mSendMessageResult;

        MessageReportedGenericArgs(int direction, int initiatorLogicalAddress,
                int destinationLogicalAddress, int opcode, int sendMessageResult) {
            this.mDirection = direction;
            this.mInitiatorLogicalAddress = initiatorLogicalAddress;
            this.mDestinationLogicalAddress = destinationLogicalAddress;
            this.mOpcode = opcode;
            this.mSendMessageResult = sendMessageResult;
        }
    }

    /**
     * Contains the opcode-dependent arguments for creating a HdmiCecMessageReported atom. Each
     * field is initialized to a null-like value by default. Therefore, a freshly constructed
     * instance of this object represents a HDMI CEC message whose type does not require any
     * additional arguments.
     */
    private class MessageReportedSpecialArgs {
        int mUserControlPressedCommand = HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN;
        int mFeatureAbortOpcode = FEATURE_ABORT_OPCODE_UNKNOWN;
        int mFeatureAbortReason = HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN;
    }
}
+15 −56
Original line number Diff line number Diff line
@@ -28,11 +28,9 @@ import android.os.Handler;
import android.os.IHwBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.stats.hdmi.HdmiStatsEnums;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
@@ -125,14 +123,10 @@ final class HdmiCecController {

    private final NativeWrapper mNativeWrapperImpl;

    private final HdmiCecAtomWriter mHdmiCecAtomWriter;

    // Private constructor.  Use HdmiCecController.create().
    private HdmiCecController(
            HdmiControlService service, NativeWrapper nativeWrapper, HdmiCecAtomWriter atomWriter) {
    private HdmiCecController(HdmiControlService service, NativeWrapper nativeWrapper) {
        mService = service;
        mNativeWrapperImpl = nativeWrapper;
        mHdmiCecAtomWriter = atomWriter;
    }

    /**
@@ -142,20 +136,19 @@ final class HdmiCecController {
     * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
     * @param service {@link HdmiControlService} instance used to create internal handler
     *                and to pass callback for incoming message or event.
     * @param atomWriter {@link HdmiCecAtomWriter} instance for writing atoms for metrics.
     * @return {@link HdmiCecController} if device is initialized successfully. Otherwise,
     *         returns {@code null}.
     */
    static HdmiCecController create(HdmiControlService service, HdmiCecAtomWriter atomWriter) {
        return createWithNativeWrapper(service, new NativeWrapperImpl(), atomWriter);
    static HdmiCecController create(HdmiControlService service) {
        return createWithNativeWrapper(service, new NativeWrapperImpl());
    }

    /**
     * A factory method with injection of native methods for testing.
     */
    static HdmiCecController createWithNativeWrapper(
            HdmiControlService service, NativeWrapper nativeWrapper, HdmiCecAtomWriter atomWriter) {
        HdmiCecController controller = new HdmiCecController(service, nativeWrapper, atomWriter);
            HdmiControlService service, NativeWrapper nativeWrapper) {
        HdmiCecController controller = new HdmiCecController(service, nativeWrapper);
        String nativePtr = nativeWrapper.nativeInit();
        if (nativePtr == null) {
            HdmiLogger.warning("Couldn't get tv.cec service.");
@@ -626,7 +619,7 @@ final class HdmiCecController {
            public void run() {
                HdmiLogger.debug("[S]:" + cecMessage);
                byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
                int retransmissionCount = 0;
                int i = 0;
                int errorCode = SendMessageResult.SUCCESS;
                do {
                    errorCode = mNativeWrapperImpl.nativeSendCecCommand(
@@ -634,26 +627,21 @@ final class HdmiCecController {
                    if (errorCode == SendMessageResult.SUCCESS) {
                        break;
                    }
                } while (retransmissionCount++ < HdmiConfig.RETRANSMISSION_COUNT);
                } while (i++ < HdmiConfig.RETRANSMISSION_COUNT);

                final int finalError = errorCode;
                if (finalError != SendMessageResult.SUCCESS) {
                    Slog.w(TAG, "Failed to send " + cecMessage + " with errorCode=" + finalError);
                }
                if (callback != null) {
                    runOnServiceThread(new Runnable() {
                        @Override
                        public void run() {
                        mHdmiCecAtomWriter.messageReported(
                                cecMessage,
                                FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED__DIRECTION__OUTGOING,
                                finalError
                        );
                        if (callback != null) {
                            callback.onSendCompleted(finalError);
                        }
                    }
                    });
                }
            }
        });
    }

@@ -666,38 +654,9 @@ final class HdmiCecController {
        HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body);
        HdmiLogger.debug("[R]:" + command);
        addCecMessageToHistory(true /* isReceived */, command);

        mHdmiCecAtomWriter.messageReported(command,
                incomingMessageDirection(srcAddress, dstAddress));

        onReceiveCommand(command);
    }

    /**
     * Computes the direction of an incoming message, as implied by the source and
     * destination addresses. This will usually return INCOMING; if not, it can indicate a bug.
     */
    private int incomingMessageDirection(int srcAddress, int dstAddress) {
        boolean sourceIsLocal = false;
        boolean destinationIsLocal = false;
        for (HdmiCecLocalDevice localDevice : getLocalDeviceList()) {
            int logicalAddress = localDevice.getDeviceInfo().getLogicalAddress();
            if (logicalAddress == srcAddress) {
                sourceIsLocal = true;
            }
            if (logicalAddress == dstAddress) {
                destinationIsLocal = true;
            }
        }

        if (!sourceIsLocal && destinationIsLocal) {
            return HdmiStatsEnums.INCOMING;
        } else if (sourceIsLocal && destinationIsLocal) {
            return HdmiStatsEnums.TO_SELF;
        }
        return HdmiStatsEnums.MESSAGE_DIRECTION_OTHER;
    }

    /**
     * Called when a hotplug event issues.
     */
+1 −14
Original line number Diff line number Diff line
@@ -397,10 +397,6 @@ public class HdmiControlService extends SystemService {
    // Set to true if the logical address allocation is completed.
    private boolean mAddressAllocated = false;

    // Object that handles logging statsd atoms.
    // Use getAtomWriter() instead of accessing directly, to allow dependency injection for testing.
    private HdmiCecAtomWriter mAtomWriter = new HdmiCecAtomWriter();

    // Buffer for processing the incoming cec messages while allocating logical addresses.
    private final class CecMessageBuffer {
        private List<HdmiCecMessage> mBuffer = new ArrayList<>();
@@ -513,7 +509,7 @@ public class HdmiControlService extends SystemService {
        mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true);

        if (mCecController == null) {
            mCecController = HdmiCecController.create(this, getAtomWriter());
            mCecController = HdmiCecController.create(this);
        }
        if (mCecController != null) {
            if (mHdmiControlEnabled) {
@@ -3237,10 +3233,6 @@ public class HdmiControlService extends SystemService {
            mActiveSource.logicalAddress = logicalAddress;
            mActiveSource.physicalAddress = physicalAddress;
        }

        getAtomWriter().activeSourceChanged(logicalAddress, physicalAddress,
                HdmiUtils.pathRelationship(getPhysicalAddress(), physicalAddress));

        // If the current device is a source device, check if the current Active Source matches
        // the local device info. Set mIsActiveSource of the local device accordingly.
        for (HdmiCecLocalDevice device : getAllLocalDevices()) {
@@ -3371,11 +3363,6 @@ public class HdmiControlService extends SystemService {
        }
    }

    @VisibleForTesting
    HdmiCecAtomWriter getAtomWriter() {
        return mAtomWriter;
    }

    boolean isMhlInputChangeEnabled() {
        synchronized (mLock) {
            return mMhlInputChangeEnabled;
+1 −1
Original line number Diff line number Diff line
@@ -110,7 +110,7 @@ public class ActiveSourceActionTest {
        mHdmiControlService.setIoLooper(looper);
        mNativeWrapper = new FakeNativeWrapper();
        HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
                this.mHdmiControlService, mNativeWrapper);
        mHdmiControlService.setCecController(hdmiCecController);
        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+2 −2
Original line number Diff line number Diff line
@@ -120,8 +120,8 @@ public class ArcInitiationActionFromAvrTest {
        Looper looper = mTestLooper.getLooper();
        mHdmiControlService.setIoLooper(looper);
        mNativeWrapper = new FakeNativeWrapper();
        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
                this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
        mHdmiCecController =
                HdmiCecController.createWithNativeWrapper(this.mHdmiControlService, mNativeWrapper);
        mHdmiControlService.setCecController(mHdmiCecController);
        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
Loading