• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.media.tv.flags.Flags.hdmiControlCollectPhysicalAddress;
20 
21 import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING;
22 import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_CONNECTED;
23 import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_PENDING;
24 import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_IDLE;
25 
26 import android.stats.hdmi.HdmiStatsEnums;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.internal.util.FrameworkStatsLog;
30 
31 /**
32  * Provides methods for writing HDMI-CEC statsd atoms.
33  */
34 @VisibleForTesting
35 public class HdmiCecAtomWriter {
36 
37     @VisibleForTesting
38     protected static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100;
39     private static final int ERROR_CODE_UNKNOWN = -1;
40     @VisibleForTesting
41     protected static final int PHYSICAL_ADDRESS_INVALID = 0xFFFF;
42 
43     /**
44      * Writes a HdmiCecMessageReported atom representing an HDMI CEC message.
45      * Should only be directly used for sent messages; for received messages,
46      * use the overloaded version with the errorCode argument omitted.
47      *
48      * @param message      The HDMI CEC message
49      * @param direction    Whether the message is incoming, outgoing, or neither
50      * @param errorCode    The error code from the final attempt to send the message
51      * @param callingUid   The calling uid of the app that triggered this message
52      */
messageReported( HdmiCecMessage message, int direction, int callingUid, int errorCode)53     public void messageReported(
54             HdmiCecMessage message, int direction, int callingUid, int errorCode) {
55         MessageReportedGenericArgs genericArgs = createMessageReportedGenericArgs(
56                 message, direction, errorCode, callingUid);
57         MessageReportedSpecialArgs specialArgs = createMessageReportedSpecialArgs(message);
58         messageReportedBase(genericArgs, specialArgs);
59     }
60 
61     /**
62      * Version of messageReported for received messages, where no error code is present.
63      *
64      * @param message      The HDMI CEC message
65      * @param direction    Whether the message is incoming, outgoing, or neither
66      * @param callingUid   The calling uid of the app that triggered this message
67      */
messageReported(HdmiCecMessage message, int direction, int callingUid)68     public void messageReported(HdmiCecMessage message, int direction, int callingUid) {
69         messageReported(message, direction, callingUid, ERROR_CODE_UNKNOWN);
70     }
71 
72     /**
73      * Constructs the generic arguments for logging a HDMI CEC message.
74      *
75      * @param message      The HDMI CEC message
76      * @param direction    Whether the message is incoming, outgoing, or neither
77      * @param errorCode    The error code of the message if it's outgoing;
78      *                     otherwise, ERROR_CODE_UNKNOWN
79      */
createMessageReportedGenericArgs( HdmiCecMessage message, int direction, int errorCode, int callingUid)80     private MessageReportedGenericArgs createMessageReportedGenericArgs(
81             HdmiCecMessage message, int direction, int errorCode, int callingUid) {
82         int sendMessageResult = errorCode == ERROR_CODE_UNKNOWN
83                 ? HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN
84                 : errorCode + 10;
85         return new MessageReportedGenericArgs(callingUid, direction, message.getSource(),
86                 message.getDestination(), message.getOpcode(), sendMessageResult);
87     }
88 
89     /**
90      * Constructs the special arguments for logging an HDMI CEC message.
91      *
92      * @param message The HDMI CEC message to log
93      * @return An object containing the special arguments for the message
94      */
createMessageReportedSpecialArgs(HdmiCecMessage message)95     private MessageReportedSpecialArgs createMessageReportedSpecialArgs(HdmiCecMessage message) {
96         // Special arguments depend on message opcode
97         switch (message.getOpcode()) {
98             case Constants.MESSAGE_USER_CONTROL_PRESSED:
99                 return createUserControlPressedSpecialArgs(message);
100             case Constants.MESSAGE_FEATURE_ABORT:
101                 return createFeatureAbortSpecialArgs(message);
102             case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
103                 if (hdmiControlCollectPhysicalAddress()) {
104                     return createReportPhysicalAddressSpecialArgs(message);
105                 }
106                 return new MessageReportedSpecialArgs();
107             default:
108                 return new MessageReportedSpecialArgs();
109         }
110     }
111 
112     /**
113      * Constructs the special arguments for a <User Control Pressed> message.
114      *
115      * @param message The HDMI CEC message to log
116      */
createUserControlPressedSpecialArgs( HdmiCecMessage message)117     private MessageReportedSpecialArgs createUserControlPressedSpecialArgs(
118             HdmiCecMessage message) {
119         MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();
120 
121         if (message.getParams().length > 0) {
122             int keycode = message.getParams()[0];
123             if (keycode >= 0x1E && keycode <= 0x29) {
124                 specialArgs.mUserControlPressedCommand = HdmiStatsEnums.NUMBER;
125             } else {
126                 specialArgs.mUserControlPressedCommand = keycode + 0x100;
127             }
128         }
129 
130         return specialArgs;
131     }
132 
133     /**
134      * Constructs the special arguments for a <Feature Abort> message.
135      *
136      * @param message The HDMI CEC message to log
137      */
createFeatureAbortSpecialArgs(HdmiCecMessage message)138     private MessageReportedSpecialArgs createFeatureAbortSpecialArgs(HdmiCecMessage message) {
139         MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();
140 
141         if (message.getParams().length > 0) {
142             specialArgs.mFeatureAbortOpcode = message.getParams()[0] & 0xFF; // Unsigned byte
143             if (message.getParams().length > 1) {
144                 specialArgs.mFeatureAbortReason = message.getParams()[1] + 10;
145             }
146         }
147 
148         return specialArgs;
149     }
150 
151     /**
152      * Constructs the special arguments for a <Report Physical Address> message.
153      *
154      * @param message The HDMI CEC message to log
155      */
createReportPhysicalAddressSpecialArgs( HdmiCecMessage message)156     private MessageReportedSpecialArgs createReportPhysicalAddressSpecialArgs(
157             HdmiCecMessage message) {
158         MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();
159 
160         if (message.getParams().length > 1) {
161             int physicalAddress = (message.getParams()[0] << 8) | message.getParams()[1];
162             specialArgs.mPhysicalAddress = physicalAddress;
163         }
164 
165         return specialArgs;
166     }
167 
168     /**
169      * Writes a HdmiCecMessageReported atom.
170      *
171      * @param genericArgs Generic arguments; shared by all HdmiCecMessageReported atoms
172      * @param specialArgs Special arguments; depends on the opcode of the message
173      */
messageReportedBase(MessageReportedGenericArgs genericArgs, MessageReportedSpecialArgs specialArgs)174     private void messageReportedBase(MessageReportedGenericArgs genericArgs,
175             MessageReportedSpecialArgs specialArgs) {
176         writeHdmiCecMessageReportedAtom(
177                 genericArgs.mUid,
178                 genericArgs.mDirection,
179                 genericArgs.mInitiatorLogicalAddress,
180                 genericArgs.mDestinationLogicalAddress,
181                 genericArgs.mOpcode,
182                 genericArgs.mSendMessageResult,
183                 specialArgs.mUserControlPressedCommand,
184                 specialArgs.mFeatureAbortOpcode,
185                 specialArgs.mFeatureAbortReason,
186                 specialArgs.mPhysicalAddress);
187     }
188 
189     /**
190      * Writes a HdmiCecMessageReported atom representing an incoming or outgoing HDMI-CEC message.
191      */
192     @VisibleForTesting
writeHdmiCecMessageReportedAtom(int uid, int direction, int initiatorLogicalAddress, int destinationLogicalAddress, int opcode, int sendMessageResult, int userControlPressedCommand, int featureAbortOpcode, int featureAbortReason, int physicalAddress)193     protected void writeHdmiCecMessageReportedAtom(int uid, int direction,
194             int initiatorLogicalAddress, int destinationLogicalAddress, int opcode,
195             int sendMessageResult, int userControlPressedCommand, int featureAbortOpcode,
196             int featureAbortReason, int physicalAddress) {
197         FrameworkStatsLog.write(
198                 FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED,
199                 uid,
200                 direction,
201                 initiatorLogicalAddress,
202                 destinationLogicalAddress,
203                 opcode,
204                 sendMessageResult,
205                 userControlPressedCommand,
206                 featureAbortOpcode,
207                 featureAbortReason,
208                 physicalAddress);
209     }
210 
211     /**
212      * Writes a HdmiCecActiveSourceChanged atom representing a change in the active source.
213      *
214      * @param logicalAddress             The Logical Address of the new active source
215      * @param physicalAddress            The Physical Address of the new active source
216      * @param relationshipToActiveSource The relationship between this device and the active source
217      */
activeSourceChanged(int logicalAddress, int physicalAddress, @Constants.PathRelationship int relationshipToActiveSource)218     public void activeSourceChanged(int logicalAddress, int physicalAddress,
219             @Constants.PathRelationship int relationshipToActiveSource) {
220         FrameworkStatsLog.write(
221                 FrameworkStatsLog.HDMI_CEC_ACTIVE_SOURCE_CHANGED,
222                 logicalAddress,
223                 physicalAddress,
224                 relationshipToActiveSource
225         );
226     }
227 
228     /**
229      * Writes a HdmiEarcStatusReported atom representing a eARC status change.
230      * @param isSupported         Whether the hardware supports eARC.
231      * @param isEnabled           Whether eARC is enabled.
232      * @param oldConnectionState  If enumLogReason == HdmiStatsEnums.LOG_REASON_EARC_STATUS_CHANGED,
233      *                            the state just before the change. Otherwise, the current state.
234      * @param newConnectionState  If enumLogReason == HdmiStatsEnums.LOG_REASON_EARC_STATUS_CHANGED,
235      *                            the state just after the change. Otherwise, the current state.
236      * @param enumLogReason       The event that triggered the log.
237      */
earcStatusChanged(boolean isSupported, boolean isEnabled, int oldConnectionState, int newConnectionState, int enumLogReason)238     public void earcStatusChanged(boolean isSupported, boolean isEnabled, int oldConnectionState,
239             int newConnectionState, int enumLogReason) {
240         int enumOldConnectionState = earcStateToEnum(oldConnectionState);
241         int enumNewConnectionState = earcStateToEnum(newConnectionState);
242 
243         FrameworkStatsLog.write(
244                 FrameworkStatsLog.HDMI_EARC_STATUS_REPORTED,
245                 isSupported,
246                 isEnabled,
247                 enumOldConnectionState,
248                 enumNewConnectionState,
249                 enumLogReason
250         );
251     }
252 
253     /**
254      * Writes a HdmiSoundbarModeStatusReported atom representing a Dynamic soundbar mode status
255      * change.
256      * @param isSupported         Whether the hardware supports ARC.
257      * @param isEnabled           Whether DSM is enabled.
258      * @param enumLogReason       The event that triggered the log.
259      */
dsmStatusChanged(boolean isSupported, boolean isEnabled, int enumLogReason)260     public void dsmStatusChanged(boolean isSupported, boolean isEnabled, int enumLogReason) {
261         FrameworkStatsLog.write(
262                 FrameworkStatsLog.HDMI_SOUNDBAR_MODE_STATUS_REPORTED,
263                 isSupported,
264                 isEnabled,
265                 enumLogReason);
266     }
267 
268     /**
269      * Writes a HdmiPowerStateChangeOnActiveSourceLostToggled atom representing a
270      * HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST setting change.
271      * @param isEnabled           Whether the setting is enabled.
272      * @param enumLogReason       The event that triggered the log.
273      * @param manufacturerPnpId   Manufacturer PNP ID reported in the EDID.
274      * @param manufacturerYear    Manufacture year reported in the EDID.
275      * @param manufacturerWeek    Manufacture week reporter in the EDID.
276      */
powerStateChangeOnActiveSourceLostChanged(boolean isEnabled, int enumLogReason, String manufacturerPnpId, int manufacturerYear, int manufacturerWeek)277     public void powerStateChangeOnActiveSourceLostChanged(boolean isEnabled, int enumLogReason,
278             String manufacturerPnpId, int manufacturerYear, int manufacturerWeek) {
279         FrameworkStatsLog.write(
280                 FrameworkStatsLog.HDMI_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLED,
281                 isEnabled,
282                 enumLogReason,
283                 manufacturerPnpId,
284                 manufacturerYear,
285                 manufacturerWeek);
286     }
287 
earcStateToEnum(int earcState)288     private int earcStateToEnum(int earcState) {
289         switch (earcState) {
290             case HDMI_EARC_STATUS_IDLE:
291                 return HdmiStatsEnums.HDMI_EARC_STATUS_IDLE;
292             case HDMI_EARC_STATUS_EARC_PENDING:
293                 return HdmiStatsEnums.HDMI_EARC_STATUS_EARC_PENDING;
294             case HDMI_EARC_STATUS_ARC_PENDING:
295                 return HdmiStatsEnums.HDMI_EARC_STATUS_ARC_PENDING;
296             case HDMI_EARC_STATUS_EARC_CONNECTED:
297                 return HdmiStatsEnums.HDMI_EARC_STATUS_EARC_CONNECTED;
298             default:
299                 return HdmiStatsEnums.HDMI_EARC_STATUS_UNKNOWN;
300         }
301     }
302 
303     /**
304      * Contains the required arguments for creating any HdmiCecMessageReported atom
305      */
306     private class MessageReportedGenericArgs {
307         final int mUid;
308         final int mDirection;
309         final int mInitiatorLogicalAddress;
310         final int mDestinationLogicalAddress;
311         final int mOpcode;
312         final int mSendMessageResult;
313 
MessageReportedGenericArgs(int uid, int direction, int initiatorLogicalAddress, int destinationLogicalAddress, int opcode, int sendMessageResult)314         MessageReportedGenericArgs(int uid, int direction, int initiatorLogicalAddress,
315                 int destinationLogicalAddress, int opcode, int sendMessageResult) {
316             this.mUid = uid;
317             this.mDirection = direction;
318             this.mInitiatorLogicalAddress = initiatorLogicalAddress;
319             this.mDestinationLogicalAddress = destinationLogicalAddress;
320             this.mOpcode = opcode;
321             this.mSendMessageResult = sendMessageResult;
322         }
323     }
324 
325     /**
326      * Contains the opcode-dependent arguments for creating a HdmiCecMessageReported atom. Each
327      * field is initialized to a null-like value by default. Therefore, a freshly constructed
328      * instance of this object represents a HDMI CEC message whose type does not require any
329      * additional arguments.
330      */
331     private class MessageReportedSpecialArgs {
332         int mUserControlPressedCommand = HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN;
333         int mFeatureAbortOpcode = FEATURE_ABORT_OPCODE_UNKNOWN;
334         int mFeatureAbortReason = HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN;
335         int mPhysicalAddress = PHYSICAL_ADDRESS_INVALID;
336     }
337 }
338