1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.hdmi; 18 19 import android.stats.hdmi.HdmiStatsEnums; 20 21 import com.android.internal.annotations.VisibleForTesting; 22 import com.android.internal.util.FrameworkStatsLog; 23 24 /** 25 * Provides methods for writing HDMI-CEC statsd atoms. 26 */ 27 @VisibleForTesting 28 public class HdmiCecAtomWriter { 29 30 private static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100; 31 private static final int ERROR_CODE_UNKNOWN = -1; 32 33 /** 34 * Writes a HdmiCecMessageReported atom representing an HDMI CEC message. 35 * Should only be directly used for sent messages; for received messages, 36 * use the overloaded version with the errorCode argument omitted. 37 * 38 * @param message The HDMI CEC message 39 * @param direction Whether the message is incoming, outgoing, or neither 40 * @param errorCode The error code from the final attempt to send the message 41 * @param callingUid The calling uid of the app that triggered this message 42 */ messageReported( HdmiCecMessage message, int direction, int callingUid, int errorCode)43 public void messageReported( 44 HdmiCecMessage message, int direction, int callingUid, int errorCode) { 45 MessageReportedGenericArgs genericArgs = createMessageReportedGenericArgs( 46 message, direction, errorCode, callingUid); 47 MessageReportedSpecialArgs specialArgs = createMessageReportedSpecialArgs(message); 48 messageReportedBase(genericArgs, specialArgs); 49 } 50 51 /** 52 * Version of messageReported for received messages, where no error code is present. 53 * 54 * @param message The HDMI CEC message 55 * @param direction Whether the message is incoming, outgoing, or neither 56 * @param callingUid The calling uid of the app that triggered this message 57 */ messageReported(HdmiCecMessage message, int direction, int callingUid)58 public void messageReported(HdmiCecMessage message, int direction, int callingUid) { 59 messageReported(message, direction, callingUid, ERROR_CODE_UNKNOWN); 60 } 61 62 /** 63 * Constructs the generic arguments for logging a HDMI CEC message. 64 * 65 * @param message The HDMI CEC message 66 * @param direction Whether the message is incoming, outgoing, or neither 67 * @param errorCode The error code of the message if it's outgoing; 68 * otherwise, ERROR_CODE_UNKNOWN 69 */ createMessageReportedGenericArgs( HdmiCecMessage message, int direction, int errorCode, int callingUid)70 private MessageReportedGenericArgs createMessageReportedGenericArgs( 71 HdmiCecMessage message, int direction, int errorCode, int callingUid) { 72 int sendMessageResult = errorCode == ERROR_CODE_UNKNOWN 73 ? HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN 74 : errorCode + 10; 75 return new MessageReportedGenericArgs(callingUid, direction, message.getSource(), 76 message.getDestination(), message.getOpcode(), sendMessageResult); 77 } 78 79 /** 80 * Constructs the special arguments for logging an HDMI CEC message. 81 * 82 * @param message The HDMI CEC message to log 83 * @return An object containing the special arguments for the message 84 */ createMessageReportedSpecialArgs(HdmiCecMessage message)85 private MessageReportedSpecialArgs createMessageReportedSpecialArgs(HdmiCecMessage message) { 86 // Special arguments depend on message opcode 87 switch (message.getOpcode()) { 88 case Constants.MESSAGE_USER_CONTROL_PRESSED: 89 return createUserControlPressedSpecialArgs(message); 90 case Constants.MESSAGE_FEATURE_ABORT: 91 return createFeatureAbortSpecialArgs(message); 92 default: 93 return new MessageReportedSpecialArgs(); 94 } 95 } 96 97 /** 98 * Constructs the special arguments for a <User Control Pressed> message. 99 * 100 * @param message The HDMI CEC message to log 101 */ createUserControlPressedSpecialArgs( HdmiCecMessage message)102 private MessageReportedSpecialArgs createUserControlPressedSpecialArgs( 103 HdmiCecMessage message) { 104 MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs(); 105 106 int keycode = message.getParams()[0]; 107 if (keycode >= 0x1E && keycode <= 0x29) { 108 specialArgs.mUserControlPressedCommand = HdmiStatsEnums.NUMBER; 109 } else { 110 specialArgs.mUserControlPressedCommand = keycode + 0x100; 111 } 112 113 return specialArgs; 114 } 115 116 /** 117 * Constructs method for constructing the special arguments for a <Feature Abort> message. 118 * 119 * @param message The HDMI CEC message to log 120 */ createFeatureAbortSpecialArgs(HdmiCecMessage message)121 private MessageReportedSpecialArgs createFeatureAbortSpecialArgs(HdmiCecMessage message) { 122 MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs(); 123 124 specialArgs.mFeatureAbortOpcode = message.getParams()[0] & 0xFF; // Unsigned byte 125 specialArgs.mFeatureAbortReason = message.getParams()[1] + 10; 126 127 return specialArgs; 128 } 129 130 /** 131 * Writes a HdmiCecMessageReported atom. 132 * 133 * @param genericArgs Generic arguments; shared by all HdmiCecMessageReported atoms 134 * @param specialArgs Special arguments; depends on the opcode of the message 135 */ messageReportedBase(MessageReportedGenericArgs genericArgs, MessageReportedSpecialArgs specialArgs)136 private void messageReportedBase(MessageReportedGenericArgs genericArgs, 137 MessageReportedSpecialArgs specialArgs) { 138 FrameworkStatsLog.write( 139 FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED, 140 genericArgs.mUid, 141 genericArgs.mDirection, 142 genericArgs.mInitiatorLogicalAddress, 143 genericArgs.mDestinationLogicalAddress, 144 genericArgs.mOpcode, 145 genericArgs.mSendMessageResult, 146 specialArgs.mUserControlPressedCommand, 147 specialArgs.mFeatureAbortOpcode, 148 specialArgs.mFeatureAbortReason); 149 } 150 151 152 /** 153 * Writes a HdmiCecActiveSourceChanged atom representing a change in the active source. 154 * 155 * @param logicalAddress The Logical Address of the new active source 156 * @param physicalAddress The Physical Address of the new active source 157 * @param relationshipToActiveSource The relationship between this device and the active source 158 */ activeSourceChanged(int logicalAddress, int physicalAddress, @Constants.PathRelationship int relationshipToActiveSource)159 public void activeSourceChanged(int logicalAddress, int physicalAddress, 160 @Constants.PathRelationship int relationshipToActiveSource) { 161 FrameworkStatsLog.write( 162 FrameworkStatsLog.HDMI_CEC_ACTIVE_SOURCE_CHANGED, 163 logicalAddress, 164 physicalAddress, 165 relationshipToActiveSource 166 ); 167 } 168 169 /** 170 * Contains the required arguments for creating any HdmiCecMessageReported atom 171 */ 172 private class MessageReportedGenericArgs { 173 final int mUid; 174 final int mDirection; 175 final int mInitiatorLogicalAddress; 176 final int mDestinationLogicalAddress; 177 final int mOpcode; 178 final int mSendMessageResult; 179 MessageReportedGenericArgs(int uid, int direction, int initiatorLogicalAddress, int destinationLogicalAddress, int opcode, int sendMessageResult)180 MessageReportedGenericArgs(int uid, int direction, int initiatorLogicalAddress, 181 int destinationLogicalAddress, int opcode, int sendMessageResult) { 182 this.mUid = uid; 183 this.mDirection = direction; 184 this.mInitiatorLogicalAddress = initiatorLogicalAddress; 185 this.mDestinationLogicalAddress = destinationLogicalAddress; 186 this.mOpcode = opcode; 187 this.mSendMessageResult = sendMessageResult; 188 } 189 } 190 191 /** 192 * Contains the opcode-dependent arguments for creating a HdmiCecMessageReported atom. Each 193 * field is initialized to a null-like value by default. Therefore, a freshly constructed 194 * instance of this object represents a HDMI CEC message whose type does not require any 195 * additional arguments. 196 */ 197 private class MessageReportedSpecialArgs { 198 int mUserControlPressedCommand = HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN; 199 int mFeatureAbortOpcode = FEATURE_ABORT_OPCODE_UNKNOWN; 200 int mFeatureAbortReason = HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN; 201 } 202 } 203