blob: 444d74dadd4a81f89c613d2f2302f1abb358ff60 [file] [log] [blame]
/*
* 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.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
/**
* Provides methods for writing HDMI-CEC statsd atoms.
*/
@VisibleForTesting
public 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
* @param callingUid The calling uid of the app that triggered this message
*/
public void messageReported(
HdmiCecMessage message, int direction, int callingUid, int errorCode) {
MessageReportedGenericArgs genericArgs = createMessageReportedGenericArgs(
message, direction, errorCode, callingUid);
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
* @param callingUid The calling uid of the app that triggered this message
*/
public void messageReported(HdmiCecMessage message, int direction, int callingUid) {
messageReported(message, direction, callingUid, 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 callingUid) {
int sendMessageResult = errorCode == ERROR_CODE_UNKNOWN
? HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN
: errorCode + 10;
return new MessageReportedGenericArgs(callingUid, 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,
genericArgs.mUid,
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 mUid;
final int mDirection;
final int mInitiatorLogicalAddress;
final int mDestinationLogicalAddress;
final int mOpcode;
final int mSendMessageResult;
MessageReportedGenericArgs(int uid, int direction, int initiatorLogicalAddress,
int destinationLogicalAddress, int opcode, int sendMessageResult) {
this.mUid = uid;
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;
}
}