• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.annotation.IntDef;
20 import android.hardware.hdmi.HdmiDeviceInfo;
21 import android.util.SparseArray;
22 
23 /**
24  * A helper class to validate {@link HdmiCecMessage}.
25  *
26  * If a message type has its own specific subclass of {@link HdmiCecMessage},
27  * validation is performed in that subclass instead.
28  */
29 public class HdmiCecMessageValidator {
30     private static final String TAG = "HdmiCecMessageValidator";
31 
32     @IntDef({
33             OK,
34             ERROR_SOURCE,
35             ERROR_DESTINATION,
36             ERROR_PARAMETER,
37             ERROR_PARAMETER_SHORT,
38             ERROR_PARAMETER_LONG,
39     })
40     public @interface ValidationResult {};
41 
42     static final int OK = 0;
43     static final int ERROR_SOURCE = 1;
44     static final int ERROR_DESTINATION = 2;
45     static final int ERROR_PARAMETER = 3;
46     static final int ERROR_PARAMETER_SHORT = 4;
47     static final int ERROR_PARAMETER_LONG = 5;
48 
49     interface ParameterValidator {
50         /**
51          * @return errorCode errorCode can be {@link #OK}, {@link #ERROR_PARAMETER} or
52          *         {@link #ERROR_PARAMETER_SHORT}.
53          */
isValid(byte[] params)54         int isValid(byte[] params);
55     }
56 
57     /**
58      * Bitmasks used for source and destination validations.
59      */
60     static final int ADDR_TV = 1 << 0;
61     static final int ADDR_RECORDER_1 = 1 << 1;
62     static final int ADDR_RECORDER_2 = 1 << 2;
63     static final int ADDR_TUNER_1 = 1 << 3;
64     static final int ADDR_PLAYBACK_1 = 1 << 4;
65     static final int ADDR_AUDIO_SYSTEM = 1 << 5;
66     static final int ADDR_TUNER_2 = 1 << 6;
67     static final int ADDR_TUNER_3 = 1 << 7;
68     static final int ADDR_PLAYBACK_2 = 1 << 8;
69     static final int ADDR_RECORDER_3 = 1 << 9;
70     static final int ADDR_TUNER_4 = 1 << 10;
71     static final int ADDR_PLAYBACK_3 = 1 << 11;
72     static final int ADDR_BACKUP_1 = 1 << 12;
73     static final int ADDR_BACKUP_2 = 1 << 13;
74     static final int ADDR_SPECIFIC_USE = 1 << 14;
75     static final int ADDR_UNREGISTERED = 1 << 15;
76     static final int ADDR_BROADCAST = 1 << 15;
77     static final int ADDR_ALL = (1 << 16) - 1;
78     static final int ADDR_DIRECT = ADDR_ALL ^ ADDR_BROADCAST;
79     static final int ADDR_NOT_UNREGISTERED = ADDR_ALL ^ ADDR_UNREGISTERED;
80 
81     private static class ValidationInfo {
82         public final ParameterValidator parameterValidator;
83         public final int validSources;
84         public final int validDestinations;
85 
ValidationInfo(ParameterValidator parameterValidator, int validSources, int validDestinations)86         ValidationInfo(ParameterValidator parameterValidator, int validSources,
87                 int validDestinations) {
88             this.parameterValidator = parameterValidator;
89             this.validSources = validSources;
90             this.validDestinations = validDestinations;
91         }
92     }
93 
HdmiCecMessageValidator()94     private HdmiCecMessageValidator() {}
95 
96     private static final SparseArray<ValidationInfo> sValidationInfo = new SparseArray<>();
97 
98     static {
99         // Messages related to the physical address.
100         PhysicalAddressValidator physicalAddressValidator = new PhysicalAddressValidator();
addValidationInfo(Constants.MESSAGE_ACTIVE_SOURCE, physicalAddressValidator, ADDR_ALL ^ ADDR_AUDIO_SYSTEM, ADDR_BROADCAST)101         addValidationInfo(Constants.MESSAGE_ACTIVE_SOURCE,
102                 physicalAddressValidator, ADDR_ALL ^ ADDR_AUDIO_SYSTEM, ADDR_BROADCAST);
addValidationInfo(Constants.MESSAGE_INACTIVE_SOURCE, physicalAddressValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)103         addValidationInfo(Constants.MESSAGE_INACTIVE_SOURCE,
104                 physicalAddressValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, new ReportPhysicalAddressValidator(), ADDR_ALL, ADDR_BROADCAST)105         addValidationInfo(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS,
106                 new ReportPhysicalAddressValidator(), ADDR_ALL, ADDR_BROADCAST);
addValidationInfo(Constants.MESSAGE_ROUTING_CHANGE, new RoutingChangeValidator(), ADDR_ALL, ADDR_BROADCAST)107         addValidationInfo(Constants.MESSAGE_ROUTING_CHANGE,
108                 new RoutingChangeValidator(), ADDR_ALL, ADDR_BROADCAST);
addValidationInfo(Constants.MESSAGE_ROUTING_INFORMATION, physicalAddressValidator, ADDR_ALL, ADDR_BROADCAST)109         addValidationInfo(Constants.MESSAGE_ROUTING_INFORMATION,
110                 physicalAddressValidator, ADDR_ALL, ADDR_BROADCAST);
addValidationInfo(Constants.MESSAGE_SET_STREAM_PATH, physicalAddressValidator, ADDR_NOT_UNREGISTERED, ADDR_BROADCAST)111         addValidationInfo(Constants.MESSAGE_SET_STREAM_PATH,
112                 physicalAddressValidator, ADDR_NOT_UNREGISTERED, ADDR_BROADCAST);
addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST, new SystemAudioModeRequestValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)113         addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
114                 new SystemAudioModeRequestValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
115 
116         // Messages have no parameter.
117         FixedLengthValidator noneValidator = new FixedLengthValidator(0);
addValidationInfo(Constants.MESSAGE_ABORT, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)118         addValidationInfo(Constants.MESSAGE_ABORT,
119                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GET_CEC_VERSION, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)120         addValidationInfo(Constants.MESSAGE_GET_CEC_VERSION,
121                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GET_MENU_LANGUAGE, noneValidator, ADDR_ALL, ADDR_DIRECT)122         addValidationInfo(Constants.MESSAGE_GET_MENU_LANGUAGE,
123                 noneValidator, ADDR_ALL, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GIVE_AUDIO_STATUS, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)124         addValidationInfo(Constants.MESSAGE_GIVE_AUDIO_STATUS,
125                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)126         addValidationInfo(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS,
127                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, noneValidator, ADDR_ALL, ADDR_DIRECT)128         addValidationInfo(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID,
129                 noneValidator, ADDR_ALL, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GIVE_OSD_NAME, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)130         addValidationInfo(Constants.MESSAGE_GIVE_OSD_NAME,
131                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, noneValidator, ADDR_ALL, ADDR_DIRECT)132         addValidationInfo(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS,
133                 noneValidator, ADDR_ALL, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)134         addValidationInfo(Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS,
135                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_IMAGE_VIEW_ON, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)136         addValidationInfo(Constants.MESSAGE_IMAGE_VIEW_ON,
137                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_INITIATE_ARC, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)138         addValidationInfo(Constants.MESSAGE_INITIATE_ARC,
139                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_RECORD_OFF, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)140         addValidationInfo(Constants.MESSAGE_RECORD_OFF,
141                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_RECORD_TV_SCREEN, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)142         addValidationInfo(Constants.MESSAGE_RECORD_TV_SCREEN,
143                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REPORT_ARC_INITIATED, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)144         addValidationInfo(Constants.MESSAGE_REPORT_ARC_INITIATED,
145                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REPORT_ARC_TERMINATED, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)146         addValidationInfo(Constants.MESSAGE_REPORT_ARC_TERMINATED,
147                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REQUEST_ARC_INITIATION, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)148         addValidationInfo(Constants.MESSAGE_REQUEST_ARC_INITIATION,
149                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REQUEST_ARC_TERMINATION, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)150         addValidationInfo(Constants.MESSAGE_REQUEST_ARC_TERMINATION,
151                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, noneValidator, ADDR_ALL, ADDR_BROADCAST)152         addValidationInfo(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE,
153                 noneValidator, ADDR_ALL, ADDR_BROADCAST);
addValidationInfo(Constants.MESSAGE_STANDBY, noneValidator, ADDR_ALL, ADDR_ALL)154         addValidationInfo(Constants.MESSAGE_STANDBY,
155                 noneValidator, ADDR_ALL, ADDR_ALL);
addValidationInfo(Constants.MESSAGE_TERMINATE_ARC, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)156         addValidationInfo(Constants.MESSAGE_TERMINATE_ARC,
157                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_TEXT_VIEW_ON, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)158         addValidationInfo(Constants.MESSAGE_TEXT_VIEW_ON,
159                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_TUNER_STEP_DECREMENT, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)160         addValidationInfo(Constants.MESSAGE_TUNER_STEP_DECREMENT,
161                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_TUNER_STEP_INCREMENT, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)162         addValidationInfo(Constants.MESSAGE_TUNER_STEP_INCREMENT,
163                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_USER_CONTROL_RELEASED, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)164         addValidationInfo(Constants.MESSAGE_USER_CONTROL_RELEASED,
165                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP, noneValidator, ADDR_NOT_UNREGISTERED, ADDR_ALL)166         addValidationInfo(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP,
167                 noneValidator, ADDR_NOT_UNREGISTERED, ADDR_ALL);
168 
169         // TODO: Validate more than length for the following messages.
170 
171         // Messages for the One Touch Record.
addValidationInfo(Constants.MESSAGE_RECORD_ON, new VariableLengthValidator(1, 8), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)172         addValidationInfo(Constants.MESSAGE_RECORD_ON,
173                 new VariableLengthValidator(1, 8), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_RECORD_STATUS, new RecordStatusInfoValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)174         addValidationInfo(Constants.MESSAGE_RECORD_STATUS,
175                 new RecordStatusInfoValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
176 
addValidationInfo(Constants.MESSAGE_CLEAR_ANALOG_TIMER, new AnalogueTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)177         addValidationInfo(Constants.MESSAGE_CLEAR_ANALOG_TIMER,
178                 new AnalogueTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_CLEAR_DIGITAL_TIMER, new DigitalTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)179         addValidationInfo(Constants.MESSAGE_CLEAR_DIGITAL_TIMER,
180                 new DigitalTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, new ExternalTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)181         addValidationInfo(Constants.MESSAGE_CLEAR_EXTERNAL_TIMER,
182                 new ExternalTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_ANALOG_TIMER, new AnalogueTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)183         addValidationInfo(Constants.MESSAGE_SET_ANALOG_TIMER,
184                 new AnalogueTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_DIGITAL_TIMER, new DigitalTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)185         addValidationInfo(Constants.MESSAGE_SET_DIGITAL_TIMER,
186                 new DigitalTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_EXTERNAL_TIMER, new ExternalTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)187         addValidationInfo(Constants.MESSAGE_SET_EXTERNAL_TIMER,
188                 new ExternalTimerValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_TIMER_PROGRAM_TITLE, new AsciiValidator(1, 14), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)189         addValidationInfo(Constants.MESSAGE_SET_TIMER_PROGRAM_TITLE,
190                 new AsciiValidator(1, 14), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_TIMER_CLEARED_STATUS, new TimerClearedStatusValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)191         addValidationInfo(Constants.MESSAGE_TIMER_CLEARED_STATUS,
192                 new TimerClearedStatusValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_TIMER_STATUS, new TimerStatusValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)193         addValidationInfo(Constants.MESSAGE_TIMER_STATUS,
194                 new TimerStatusValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
195 
196         // Messages for the System Information.
197         FixedLengthValidator oneByteValidator = new FixedLengthValidator(1);
addValidationInfo(Constants.MESSAGE_CEC_VERSION, oneByteValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)198         addValidationInfo(Constants.MESSAGE_CEC_VERSION,
199                 oneByteValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE, new AsciiValidator(3), ADDR_TV, ADDR_BROADCAST)200         addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE,
201                 new AsciiValidator(3), ADDR_TV, ADDR_BROADCAST);
202 
203         ParameterValidator statusRequestValidator = new MinimumOneByteRangeValidator(0x01, 0x03);
addValidationInfo(Constants.MESSAGE_DECK_CONTROL, new MinimumOneByteRangeValidator(0x01, 0x04), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)204         addValidationInfo(Constants.MESSAGE_DECK_CONTROL,
205                 new MinimumOneByteRangeValidator(0x01, 0x04), ADDR_NOT_UNREGISTERED,
206                 ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_DECK_STATUS, new MinimumOneByteRangeValidator(0x11, 0x1F), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)207         addValidationInfo(Constants.MESSAGE_DECK_STATUS,
208                 new MinimumOneByteRangeValidator(0x11, 0x1F), ADDR_NOT_UNREGISTERED,
209                 ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_GIVE_DECK_STATUS, statusRequestValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)210         addValidationInfo(Constants.MESSAGE_GIVE_DECK_STATUS,
211                 statusRequestValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_PLAY, new PlayModeValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)212         addValidationInfo(Constants.MESSAGE_PLAY,
213                 new PlayModeValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
214 
addValidationInfo(Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS, statusRequestValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)215         addValidationInfo(Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS,
216                 statusRequestValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SELECT_ANALOG_SERVICE, new SelectAnalogueServiceValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)217         addValidationInfo(Constants.MESSAGE_SELECT_ANALOG_SERVICE,
218                 new SelectAnalogueServiceValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SELECT_DIGITAL_SERVICE, new SelectDigitalServiceValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)219         addValidationInfo(Constants.MESSAGE_SELECT_DIGITAL_SERVICE,
220                 new SelectDigitalServiceValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_TUNER_DEVICE_STATUS, new TunerDeviceStatusValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)221         addValidationInfo(Constants.MESSAGE_TUNER_DEVICE_STATUS,
222                 new TunerDeviceStatusValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
223 
224         // Messages for the Vendor Specific Commands.
225         VariableLengthValidator maxLengthValidator = new VariableLengthValidator(0, 14);
addValidationInfo(Constants.MESSAGE_DEVICE_VENDOR_ID, new FixedLengthValidator(3), ADDR_NOT_UNREGISTERED, ADDR_BROADCAST)226         addValidationInfo(Constants.MESSAGE_DEVICE_VENDOR_ID,
227                 new FixedLengthValidator(3), ADDR_NOT_UNREGISTERED, ADDR_BROADCAST);
228         // Allow unregistered source for all vendor specific commands, because we don't know
229         // how to use the commands at this moment.
addValidationInfo(Constants.MESSAGE_VENDOR_COMMAND, new VariableLengthValidator(1, 14), ADDR_ALL, ADDR_DIRECT)230         addValidationInfo(Constants.MESSAGE_VENDOR_COMMAND,
231                 new VariableLengthValidator(1, 14), ADDR_ALL, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, new VariableLengthValidator(4, 14), ADDR_ALL, ADDR_ALL)232         addValidationInfo(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID,
233                 new VariableLengthValidator(4, 14), ADDR_ALL, ADDR_ALL);
addValidationInfo(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN, maxLengthValidator, ADDR_ALL, ADDR_ALL)234         addValidationInfo(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN,
235                 maxLengthValidator, ADDR_ALL, ADDR_ALL);
236 
237         // Messages for the OSD.
addValidationInfo(Constants.MESSAGE_SET_OSD_STRING, new OsdStringValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)238         addValidationInfo(Constants.MESSAGE_SET_OSD_STRING,
239                 new OsdStringValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_OSD_NAME, new AsciiValidator(1, 14), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)240         addValidationInfo(Constants.MESSAGE_SET_OSD_NAME,
241                 new AsciiValidator(1, 14), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
242 
243         // Messages for the Device Menu Control.
addValidationInfo(Constants.MESSAGE_MENU_REQUEST, new MinimumOneByteRangeValidator(0x00, 0x02), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)244         addValidationInfo(Constants.MESSAGE_MENU_REQUEST,
245                 new MinimumOneByteRangeValidator(0x00, 0x02), ADDR_NOT_UNREGISTERED,
246                 ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_MENU_STATUS, new MinimumOneByteRangeValidator(0x00, 0x01), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)247         addValidationInfo(Constants.MESSAGE_MENU_STATUS,
248                 new MinimumOneByteRangeValidator(0x00, 0x01), ADDR_NOT_UNREGISTERED,
249                 ADDR_DIRECT);
250 
251         // Messages for the Remote Control Passthrough.
addValidationInfo(Constants.MESSAGE_USER_CONTROL_PRESSED, new UserControlPressedValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)252         addValidationInfo(Constants.MESSAGE_USER_CONTROL_PRESSED,
253                 new UserControlPressedValidator(), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
254 
255         // Messages for the Power Status.
addValidationInfo(Constants.MESSAGE_REPORT_POWER_STATUS, new MinimumOneByteRangeValidator(0x00, 0x03), ADDR_NOT_UNREGISTERED, ADDR_ALL)256         addValidationInfo(Constants.MESSAGE_REPORT_POWER_STATUS,
257                 new MinimumOneByteRangeValidator(0x00, 0x03),
258                 ADDR_NOT_UNREGISTERED, ADDR_ALL);
259 
260         // Messages for the General Protocol.
addValidationInfo(Constants.MESSAGE_FEATURE_ABORT, new FixedLengthValidator(2), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)261         addValidationInfo(Constants.MESSAGE_FEATURE_ABORT,
262                 new FixedLengthValidator(2), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
263 
264         // Messages for the System Audio Control.
addValidationInfo(Constants.MESSAGE_REPORT_AUDIO_STATUS, oneByteValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)265         addValidationInfo(Constants.MESSAGE_REPORT_AUDIO_STATUS,
266                 oneByteValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, new FixedLengthValidator(3), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)267         addValidationInfo(Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR,
268                 new FixedLengthValidator(3), ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, oneByteValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT)269         addValidationInfo(Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
270                 oneByteValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, new SingleByteRangeValidator(0x00, 0x01), ADDR_AUDIO_SYSTEM, ADDR_ALL)271         addValidationInfo(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE,
272                 new SingleByteRangeValidator(0x00, 0x01), ADDR_AUDIO_SYSTEM, ADDR_ALL);
addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, new SingleByteRangeValidator(0x00, 0x01), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)273         addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS,
274                 new SingleByteRangeValidator(0x00, 0x01), ADDR_NOT_UNREGISTERED,
275                 ADDR_DIRECT);
276 
277         // Messages for the Audio Rate Control.
addValidationInfo(Constants.MESSAGE_SET_AUDIO_RATE, new MinimumOneByteRangeValidator(0x00, 0x06), ADDR_NOT_UNREGISTERED, ADDR_DIRECT)278         addValidationInfo(Constants.MESSAGE_SET_AUDIO_RATE,
279                 new MinimumOneByteRangeValidator(0x00, 0x06), ADDR_NOT_UNREGISTERED,
280                 ADDR_DIRECT);
281 
282         // Messages for Feature Discovery.
addValidationInfo(Constants.MESSAGE_GIVE_FEATURES, noneValidator, ADDR_ALL, ADDR_DIRECT)283         addValidationInfo(Constants.MESSAGE_GIVE_FEATURES,
284                 noneValidator, ADDR_ALL, ADDR_DIRECT);
285 
286         // Messages for Dynamic Auto Lipsync
addValidationInfo(Constants.MESSAGE_REQUEST_CURRENT_LATENCY, physicalAddressValidator, ADDR_NOT_UNREGISTERED, ADDR_BROADCAST)287         addValidationInfo(Constants.MESSAGE_REQUEST_CURRENT_LATENCY,
288                 physicalAddressValidator, ADDR_NOT_UNREGISTERED, ADDR_BROADCAST);
addValidationInfo(Constants.MESSAGE_REPORT_CURRENT_LATENCY, new VariableLengthValidator(4, 14), ADDR_NOT_UNREGISTERED, ADDR_BROADCAST)289         addValidationInfo(Constants.MESSAGE_REPORT_CURRENT_LATENCY,
290                 new VariableLengthValidator(4, 14), ADDR_NOT_UNREGISTERED, ADDR_BROADCAST);
291 
292         // All Messages for the ARC have no parameters.
293 
294         // Messages for the Capability Discovery and Control.
addValidationInfo(Constants.MESSAGE_CDC_MESSAGE, maxLengthValidator, ADDR_ALL, ADDR_BROADCAST)295         addValidationInfo(Constants.MESSAGE_CDC_MESSAGE,
296                 maxLengthValidator, ADDR_ALL, ADDR_BROADCAST);
297     }
298 
299     /**
300      * validSources and validDestinations are bitmasks that represent the sources and destinations
301      * that are allowed for a message.
302      */
addValidationInfo(int opcode, ParameterValidator validator, int validSources, int validDestinations)303     private static void addValidationInfo(int opcode, ParameterValidator validator,
304             int validSources, int validDestinations) {
305         sValidationInfo.append(opcode, new ValidationInfo(validator, validSources,
306                 validDestinations));
307     }
308 
309     /**
310      * Validates all parameters of a HDMI-CEC message using static information stored in this class.
311      */
312     @ValidationResult
validate(int source, int destination, int opcode, byte[] params)313     static int validate(int source, int destination, int opcode, byte[] params) {
314         ValidationInfo info = sValidationInfo.get(opcode);
315 
316         if (info == null) {
317             HdmiLogger.warning("No validation information for the opcode: " + opcode);
318             return OK;
319         }
320 
321         int addressValidationResult = validateAddress(source, destination, info.validSources,
322                 info.validDestinations);
323         if (addressValidationResult != OK) {
324             return addressValidationResult;
325         }
326 
327         // Validate parameters
328         int errorCode = info.parameterValidator.isValid(params);
329         if (errorCode != OK) {
330             return errorCode;
331         }
332 
333         return OK;
334     }
335 
336     /**
337      * Validates the source and destination addresses of a HDMI-CEC message according to input
338      * address type. Allows address validation logic to be expressed concisely without depending
339      * on static information in this class.
340      * @param source Source address to validate
341      * @param destination Destination address to validate
342      * @param validSources Bitmask used to validate the source address
343      *                     - e.g. {@link #ADDR_SOURCE_DEVICES}
344      * @param validDestinations Bitmask used to validate the destination address
345      *                        - e.g. {@link #ADDR_DIRECT}
346      */
347     @ValidationResult
validateAddress(int source, int destination, int validSources, int validDestinations)348     static int validateAddress(int source, int destination, int validSources,
349             int validDestinations) {
350         // Check the source field.
351         if ((validSources & (1 << source)) == 0) {
352             return ERROR_SOURCE;
353         }
354         // Check the destination field.
355         if ((validDestinations & (1 << destination)) == 0) {
356             return ERROR_DESTINATION;
357         }
358         return OK;
359     }
360 
361     private static class FixedLengthValidator implements ParameterValidator {
362         private final int mLength;
363 
FixedLengthValidator(int length)364         public FixedLengthValidator(int length) {
365             mLength = length;
366         }
367 
368         @Override
isValid(byte[] params)369         public int isValid(byte[] params) {
370             // If the length is longer than expected, we assume it's OK since the parameter can be
371             // extended in the future version.
372             return params.length < mLength ? ERROR_PARAMETER_SHORT : OK;
373         }
374     }
375 
376     private static class VariableLengthValidator implements ParameterValidator {
377         private final int mMinLength;
378         private final int mMaxLength;
379 
VariableLengthValidator(int minLength, int maxLength)380         public VariableLengthValidator(int minLength, int maxLength) {
381             mMinLength = minLength;
382             mMaxLength = maxLength;
383         }
384 
385         @Override
isValid(byte[] params)386         public int isValid(byte[] params) {
387             return params.length < mMinLength ? ERROR_PARAMETER_SHORT : OK;
388         }
389     }
390 
isValidPhysicalAddress(byte[] params, int offset)391     private static boolean isValidPhysicalAddress(byte[] params, int offset) {
392         int physicalAddress = HdmiUtils.twoBytesToInt(params, offset);
393         if (physicalAddress == 0xFFFF) {
394             return false;
395         }
396         while (physicalAddress != 0) {
397             int maskedAddress = physicalAddress & 0xF000;
398             physicalAddress = (physicalAddress << 4) & 0xFFFF;
399             if (maskedAddress == 0 && physicalAddress != 0) {
400                 return false;
401             }
402         }
403         return true;
404     }
405 
406     /**
407      * Check if the given type is valid. A valid type is one of the actual logical device types
408      * defined in the standard ({@link HdmiDeviceInfo#DEVICE_TV},
409      * {@link HdmiDeviceInfo#DEVICE_PLAYBACK}, {@link HdmiDeviceInfo#DEVICE_TUNER},
410      * {@link HdmiDeviceInfo#DEVICE_RECORDER}, and {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}).
411      *
412      * @param type device type
413      * @return true if the given type is valid
414      */
isValidType(int type)415     static boolean isValidType(int type) {
416         return (HdmiDeviceInfo.DEVICE_TV <= type
417                 && type <= HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR)
418                 && type != HdmiDeviceInfo.DEVICE_RESERVED;
419     }
420 
toErrorCode(boolean success)421     private static int toErrorCode(boolean success) {
422         return success ? OK : ERROR_PARAMETER;
423     }
424 
isWithinRange(int value, int min, int max)425     private static boolean isWithinRange(int value, int min, int max) {
426         value = value & 0xFF;
427         return (value >= min && value <= max);
428     }
429 
430     /**
431      * Check if the given value is a valid Display Control. A valid value is one which falls within
432      * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
433      *
434      * @param value Display Control
435      * @return true if the Display Control is valid
436      */
isValidDisplayControl(int value)437     private static boolean isValidDisplayControl(int value) {
438         value = value & 0xFF;
439         return (value == 0x00 || value == 0x40 || value == 0x80 || value == 0xC0);
440     }
441 
442     /**
443      * Check if the given params has valid ASCII characters.
444      * A valid ASCII character is a printable character. It should fall within range description
445      * defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
446      *
447      * @param params parameter consisting of string
448      * @param offset Start offset of string
449      * @param maxLength Maximum length of string to be evaluated
450      * @return true if the given type is valid
451      */
isValidAsciiString(byte[] params, int offset, int maxLength)452     private static boolean isValidAsciiString(byte[] params, int offset, int maxLength) {
453         for (int i = offset; i < params.length && i < maxLength; i++) {
454             if (!isWithinRange(params[i], 0x20, 0x7E)) {
455                 return false;
456             }
457         }
458         return true;
459     }
460 
461     /**
462      * Check if the given value is a valid day of month. A valid value is one which falls within the
463      * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
464      *
465      * @param value day of month
466      * @return true if the day of month is valid
467      */
isValidDayOfMonth(int value)468     private static boolean isValidDayOfMonth(int value) {
469         return isWithinRange(value, 1, 31);
470     }
471 
472     /**
473      * Check if the given value is a valid month of year. A valid value is one which falls within
474      * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
475      *
476      * @param value month of year
477      * @return true if the month of year is valid
478      */
isValidMonthOfYear(int value)479     private static boolean isValidMonthOfYear(int value) {
480         return isWithinRange(value, 1, 12);
481     }
482 
483     /**
484      * Check if the given value is a valid hour. A valid value is one which falls within the range
485      * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
486      *
487      * @param value hour
488      * @return true if the hour is valid
489      */
isValidHour(int value)490     private static boolean isValidHour(int value) {
491         value = bcdToDecimal(value);
492         return isWithinRange(value, 0, 23);
493     }
494 
495     /**
496      * Check if the given value is a valid minute. A valid value is one which falls within the range
497      * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
498      *
499      * @param value minute
500      * @return true if the minute is valid
501      */
isValidMinute(int value)502     private static boolean isValidMinute(int value) {
503         value = bcdToDecimal(value);
504         return isWithinRange(value, 0, 59);
505     }
506 
507     /**
508      * Check if the given value is a valid duration hours. A valid value is one which falls within
509      * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
510      *
511      * @param value duration hours
512      * @return true if the duration hours is valid
513      */
isValidDurationHours(int value)514     private static boolean isValidDurationHours(int value) {
515         value = bcdToDecimal(value);
516         return isWithinRange(value, 0, 99);
517     }
518 
519     /**
520      * Convert BCD value to decimal value.
521      *
522      * @param value BCD value
523      * @return decimal value
524      */
bcdToDecimal(int value)525     private static int bcdToDecimal(int value) {
526         int tens = (value & 0xF0) >> 4;
527         int ones = (value & 0x0F);
528 
529         return tens * 10 + ones;
530     }
531 
532     /**
533      * Check if the given value is a valid recording sequence. A valid value is adheres to range
534      * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
535      *
536      * @param value recording sequence
537      * @return true if the given recording sequence is valid
538      */
isValidRecordingSequence(int value)539     private static boolean isValidRecordingSequence(int value) {
540         value = value & 0xFF;
541         // Validate bit 7 is set to zero
542         if ((value & 0x80) != 0x00) {
543             return false;
544         }
545         return true;
546     }
547 
548     /**
549      * Check if the given value is a valid analogue broadcast type. A valid value is one which falls
550      * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
551      * 17)
552      *
553      * @param value analogue broadcast type
554      * @return true if the analogue broadcast type is valid
555      */
isValidAnalogueBroadcastType(int value)556     private static boolean isValidAnalogueBroadcastType(int value) {
557         return isWithinRange(value, 0x00, 0x02);
558     }
559 
560     /**
561      * Check if the given value is a valid analogue frequency. A valid value is one which falls
562      * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
563      * 17)
564      *
565      * @param value analogue frequency
566      * @return true if the analogue frequency is valid
567      */
isValidAnalogueFrequency(int value)568     private static boolean isValidAnalogueFrequency(int value) {
569         value = value & 0xFFFF;
570         return (value != 0x000 && value != 0xFFFF);
571     }
572 
573     /**
574      * Check if the given value is a valid broadcast system. A valid value is one which falls within
575      * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
576      *
577      * @param value broadcast system
578      * @return true if the broadcast system is valid
579      */
isValidBroadcastSystem(int value)580     private static boolean isValidBroadcastSystem(int value) {
581         return isWithinRange(value, 0, 31);
582     }
583 
584     /**
585      * Check if the given value is a ARIB type. A valid value is one which falls within the range
586      * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
587      *
588      * @param value Digital Broadcast System
589      * @return true if the Digital Broadcast System is ARIB type
590      */
isAribDbs(int value)591     private static boolean isAribDbs(int value) {
592         return (value == 0x00 || isWithinRange(value, 0x08, 0x0A));
593     }
594 
595     /**
596      * Check if the given value is a ATSC type. A valid value is one which falls within the range
597      * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
598      *
599      * @param value Digital Broadcast System
600      * @return true if the Digital Broadcast System is ATSC type
601      */
isAtscDbs(int value)602     private static boolean isAtscDbs(int value) {
603         return (value == 0x01 || isWithinRange(value, 0x10, 0x12));
604     }
605 
606     /**
607      * Check if the given value is a DVB type. A valid value is one which falls within the range
608      * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
609      *
610      * @param value Digital Broadcast System
611      * @return true if the Digital Broadcast System is DVB type
612      */
isDvbDbs(int value)613     private static boolean isDvbDbs(int value) {
614         return (value == 0x02 || isWithinRange(value, 0x18, 0x1B));
615     }
616 
617     /**
618      * Check if the given value is a valid Digital Broadcast System. A valid value is one which
619      * falls within the range description defined in CEC 1.4 Specification : Operand Descriptions
620      * (Section 17)
621      *
622      * @param value Digital Broadcast System
623      * @return true if the Digital Broadcast System is valid
624      */
isValidDigitalBroadcastSystem(int value)625     private static boolean isValidDigitalBroadcastSystem(int value) {
626         return (isAribDbs(value) || isAtscDbs(value) || isDvbDbs(value));
627     }
628 
629     /**
630      * Check if the given value is a valid Channel Identifier. A valid value is one which falls
631      * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
632      * 17)
633      *
634      * @param params Channel Identifier parameters
635      * @param offset start offset of Channel Identifier
636      * @return true if the Channel Identifier is valid
637      */
isValidChannelIdentifier(byte[] params, int offset)638     private static boolean isValidChannelIdentifier(byte[] params, int offset) {
639         // First 6 bits contain Channel Number Format
640         int channelNumberFormat = params[offset] & 0xFC;
641         if (channelNumberFormat == 0x04) {
642             // Validate it contains 1-part Channel Number data (16 bits)
643             return params.length - offset >= 3;
644         } else if (channelNumberFormat == 0x08) {
645             // Validate it contains Major Channel Number and Minor Channel Number (26 bits)
646             return params.length - offset >= 4;
647         }
648         return false;
649     }
650 
651     /**
652      * Check if the given value is a valid Digital Service Identification. A valid value is one
653      * which falls within the range description defined in CEC 1.4 Specification : Operand
654      * Descriptions (Section 17)
655      *
656      * @param params Digital Timer Message parameters
657      * @param offset start offset of Digital Service Identification
658      * @return true if the Digital Service Identification is valid
659      */
isValidDigitalServiceIdentification(byte[] params, int offset)660     private static boolean isValidDigitalServiceIdentification(byte[] params, int offset) {
661         // MSB contains Service Identification Method
662         int serviceIdentificationMethod = params[offset] & 0x80;
663         // Last 7 bits contains Digital Broadcast System
664         int digitalBroadcastSystem = params[offset] & 0x7F;
665         offset = offset + 1;
666         if (serviceIdentificationMethod == 0x00) {
667             // Services identified by Digital IDs
668             if (isAribDbs(digitalBroadcastSystem)) {
669                 // Validate ARIB type have 6 byte data
670                 return params.length - offset >= 6;
671             } else if (isAtscDbs(digitalBroadcastSystem)) {
672                 // Validate ATSC type have 4 byte data
673                 return params.length - offset >= 4;
674             } else if (isDvbDbs(digitalBroadcastSystem)) {
675                 // Validate DVB type have 6 byte data
676                 return params.length - offset >= 6;
677             }
678         } else if (serviceIdentificationMethod == 0x80) {
679             // Services identified by Channel
680             if (isValidDigitalBroadcastSystem(digitalBroadcastSystem)) {
681                 return isValidChannelIdentifier(params, offset);
682             }
683         }
684         return false;
685     }
686 
687     /**
688      * Check if the given value is a valid External Plug. A valid value is one which falls within
689      * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
690      *
691      * @param value External Plug
692      * @return true if the External Plug is valid
693      */
isValidExternalPlug(int value)694     private static boolean isValidExternalPlug(int value) {
695         return isWithinRange(value, 1, 255);
696     }
697 
698     /**
699      * Check if the given value is a valid External Source. A valid value is one which falls within
700      * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
701      *
702      * @param value External Source Specifier
703      * @return true if the External Source is valid
704      */
isValidExternalSource(byte[] params, int offset)705     private static boolean isValidExternalSource(byte[] params, int offset) {
706         int externalSourceSpecifier = params[offset];
707         offset = offset + 1;
708         if (externalSourceSpecifier == 0x04) {
709             // External Plug
710             return isValidExternalPlug(params[offset]);
711         } else if (externalSourceSpecifier == 0x05) {
712             // External Physical Address
713             // Validate it contains 2 bytes Physical Address
714             if (params.length - offset >= 2) {
715                 return isValidPhysicalAddress(params, offset);
716             }
717         }
718         return false;
719     }
720 
isValidProgrammedInfo(int programedInfo)721     private static boolean isValidProgrammedInfo(int programedInfo) {
722         return (isWithinRange(programedInfo, 0x00, 0x0B));
723     }
724 
isValidNotProgrammedErrorInfo(int nonProgramedErrorInfo)725     private static boolean isValidNotProgrammedErrorInfo(int nonProgramedErrorInfo) {
726         return (isWithinRange(nonProgramedErrorInfo, 0x00, 0x0E));
727     }
728 
isValidTimerStatusData(byte[] params, int offset)729     private static boolean isValidTimerStatusData(byte[] params, int offset) {
730         int programedIndicator = params[offset] & 0x10;
731         boolean durationAvailable = false;
732         if (programedIndicator == 0x10) {
733             // Programmed
734             int programedInfo = params[offset] & 0x0F;
735             if (isValidProgrammedInfo(programedInfo)) {
736                 offset = offset + 1;
737                 // Duration Available (2 bytes)
738                 if ((programedInfo == 0x09 || programedInfo == 0x0B)
739                         && params.length - offset >= 2) {
740                     durationAvailable = true;
741                 } else {
742                     return true;
743                 }
744             }
745         } else {
746             // Non programmed
747             int nonProgramedErrorInfo = params[offset] & 0x0F;
748             if (isValidNotProgrammedErrorInfo(nonProgramedErrorInfo)) {
749                 offset = offset + 1;
750                 // Duration Available (2 bytes)
751                 if (nonProgramedErrorInfo == 0x0E && params.length - offset >= 2) {
752                     durationAvailable = true;
753                 } else {
754                     return true;
755                 }
756             }
757         }
758         // Duration Available (2 bytes)
759         if (durationAvailable) {
760             return (isValidDurationHours(params[offset]) && isValidMinute(params[offset + 1]));
761         }
762         return false;
763     }
764 
765     /**
766      * Check if the given value is a valid Play mode. A valid value is one which falls within the
767      * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
768      *
769      * @param value Play mode
770      * @return true if the Play mode is valid
771      */
isValidPlayMode(int value)772     private static boolean isValidPlayMode(int value) {
773         return (isWithinRange(value, 0x05, 0x07)
774                 || isWithinRange(value, 0x09, 0x0B)
775                 || isWithinRange(value, 0x15, 0x17)
776                 || isWithinRange(value, 0x19, 0x1B)
777                 || isWithinRange(value, 0x24, 0x25)
778                 || (value == 0x20));
779     }
780 
781     /**
782      * Check if the given value is a valid UI Broadcast type. A valid value is one which falls
783      * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
784      * 17)
785      *
786      * @param value UI Broadcast type
787      * @return true if the UI Broadcast type is valid
788      */
isValidUiBroadcastType(int value)789     private static boolean isValidUiBroadcastType(int value) {
790         value = value & 0xFF;
791         return ((value == 0x00)
792                 || (value == 0x01)
793                 || (value == 0x10)
794                 || (value == 0x20)
795                 || (value == 0x30)
796                 || (value == 0x40)
797                 || (value == 0x50)
798                 || (value == 0x60)
799                 || (value == 0x70)
800                 || (value == 0x80)
801                 || (value == 0x90)
802                 || (value == 0x91)
803                 || (value == 0xA0));
804     }
805 
806     /**
807      * Check if the given value is a valid UI Sound Presenation Control. A valid value is one which
808      * falls within the range description defined in CEC 1.4 Specification : Operand Descriptions
809      * (Section 17)
810      *
811      * @param value UI Sound Presenation Control
812      * @return true if the UI Sound Presenation Control is valid
813      */
isValidUiSoundPresenationControl(int value)814     private static boolean isValidUiSoundPresenationControl(int value) {
815         value = value & 0xFF;
816         return ((value == 0x20)
817                 || (value == 0x30)
818                 || (value == 0x80)
819                 || (value == 0x90)
820                 || (value == 0xA0)
821                 || (isWithinRange(value, 0xB1, 0xB3))
822                 || (isWithinRange(value, 0xC1, 0xC3)));
823     }
824 
825     /*
826      * Check if the given value is a valid Tuner Device info. A valid value is one which falls
827      * within the range description defined in CEC 1.4 Specification : Operand Descriptions
828      * (Section 17)
829      *
830      * @param params Tuner device info
831      * @return true if the Tuner device info is valid
832      */
isValidTunerDeviceInfo(byte[] params)833     private static boolean isValidTunerDeviceInfo(byte[] params) {
834         int tunerDisplayInfo = params[0] & 0x7F;
835         if (tunerDisplayInfo == 0x00) {
836             // Displaying digital tuner
837             if (params.length >= 5) {
838                 return isValidDigitalServiceIdentification(params, 1);
839             }
840         } else if (tunerDisplayInfo == 0x01) {
841             // Not displaying Tuner
842             return true;
843         } else if (tunerDisplayInfo == 0x02) {
844             // Displaying Analogue tuner
845             if (params.length >= 5) {
846                 return (isValidAnalogueBroadcastType(params[1])
847                         && isValidAnalogueFrequency(HdmiUtils.twoBytesToInt(params, 2))
848                         && isValidBroadcastSystem(params[4]));
849             }
850         }
851         return false;
852     }
853 
854     private static class PhysicalAddressValidator implements ParameterValidator {
855         @Override
isValid(byte[] params)856         public int isValid(byte[] params) {
857             if (params.length < 2) {
858                 return ERROR_PARAMETER_SHORT;
859             }
860             return toErrorCode(isValidPhysicalAddress(params, 0));
861         }
862     }
863 
864     private static class SystemAudioModeRequestValidator extends PhysicalAddressValidator {
865         @Override
isValid(byte[] params)866         public int isValid(byte[] params) {
867             // TV can send <System Audio Mode Request> with no parameters to terminate system audio.
868             if (params.length == 0) {
869                 return OK;
870             }
871             return super.isValid(params);
872         }
873     }
874 
875     private static class ReportPhysicalAddressValidator implements ParameterValidator {
876         @Override
isValid(byte[] params)877         public int isValid(byte[] params) {
878             if (params.length < 3) {
879                 return ERROR_PARAMETER_SHORT;
880             }
881             return toErrorCode(isValidPhysicalAddress(params, 0) && isValidType(params[2]));
882         }
883     }
884 
885     private static class RoutingChangeValidator implements ParameterValidator {
886         @Override
isValid(byte[] params)887         public int isValid(byte[] params) {
888             if (params.length < 4) {
889                 return ERROR_PARAMETER_SHORT;
890             }
891             return toErrorCode(
892                     isValidPhysicalAddress(params, 0) && isValidPhysicalAddress(params, 2));
893         }
894     }
895 
896     /**
897      * Check if the given record status message parameter is valid.
898      * A valid parameter should lie within the range description of Record Status Info defined in
899      * CEC 1.4 Specification : Operand Descriptions (Section 17)
900      */
901     private static class RecordStatusInfoValidator implements ParameterValidator {
902         @Override
isValid(byte[] params)903         public int isValid(byte[] params) {
904             if (params.length < 1) {
905                 return ERROR_PARAMETER_SHORT;
906             }
907             return toErrorCode(isWithinRange(params[0], 0x01, 0x07)
908                             || isWithinRange(params[0], 0x09, 0x0E)
909                             || isWithinRange(params[0], 0x10, 0x17)
910                             || isWithinRange(params[0], 0x1A, 0x1B)
911                             || params[0] == 0x1F);
912         }
913     }
914 
915     /**
916      * Check if the given parameters represents printable characters.
917      * A valid parameter should lie within the range description of ASCII defined in CEC 1.4
918      * Specification : Operand Descriptions (Section 17)
919      */
920     private static class AsciiValidator implements ParameterValidator {
921         private final int mMinLength;
922         private final int mMaxLength;
923 
AsciiValidator(int length)924         AsciiValidator(int length) {
925             mMinLength = length;
926             mMaxLength = length;
927         }
928 
AsciiValidator(int minLength, int maxLength)929         AsciiValidator(int minLength, int maxLength) {
930             mMinLength = minLength;
931             mMaxLength = maxLength;
932         }
933 
934         @Override
isValid(byte[] params)935         public int isValid(byte[] params) {
936             // If the length is longer than expected, we assume it's OK since the parameter can be
937             // extended in the future version.
938             if (params.length < mMinLength) {
939                 return ERROR_PARAMETER_SHORT;
940             }
941             return toErrorCode(isValidAsciiString(params, 0, mMaxLength));
942         }
943     }
944 
945     /**
946      * Check if the given parameters is valid OSD String.
947      * A valid parameter should lie within the range description of ASCII defined in CEC 1.4
948      * Specification : Operand Descriptions (Section 17)
949      */
950     private static class OsdStringValidator implements ParameterValidator {
951         @Override
isValid(byte[] params)952         public int isValid(byte[] params) {
953             // If the length is longer than expected, we assume it's OK since the parameter can be
954             // extended in the future version.
955             if (params.length < 2) {
956                 return ERROR_PARAMETER_SHORT;
957             }
958             return toErrorCode(
959                     // Display Control
960                     isValidDisplayControl(params[0])
961                     // OSD String
962                     && isValidAsciiString(params, 1, 14));
963         }
964     }
965 
966     /**
967      * Check if the given parameters are at least one byte parameters
968      * and the first byte is within range.
969      */
970     private static class MinimumOneByteRangeValidator implements ParameterValidator {
971         private final int mMinValue, mMaxValue;
972 
MinimumOneByteRangeValidator(int minValue, int maxValue)973         MinimumOneByteRangeValidator(int minValue, int maxValue) {
974             mMinValue = minValue;
975             mMaxValue = maxValue;
976         }
977 
978         @Override
isValid(byte[] params)979         public int isValid(byte[] params) {
980             if (params.length < 1) {
981                 return ERROR_PARAMETER_SHORT;
982             }
983             return toErrorCode(isWithinRange(params[0], mMinValue, mMaxValue));
984         }
985     }
986 
987     /** Check if the given parameters are exactly one byte parameters and within range. */
988     private static class SingleByteRangeValidator implements ParameterValidator {
989         private final int mMinValue, mMaxValue;
990 
SingleByteRangeValidator(int minValue, int maxValue)991         SingleByteRangeValidator(int minValue, int maxValue) {
992             mMinValue = minValue;
993             mMaxValue = maxValue;
994         }
995 
996         @Override
isValid(byte[] params)997         public int isValid(byte[] params) {
998             if (params.length < 1) {
999                 return ERROR_PARAMETER_SHORT;
1000             } else if (params.length > 1) {
1001                 return ERROR_PARAMETER_LONG;
1002             }
1003             return toErrorCode(isWithinRange(params[0], mMinValue, mMaxValue));
1004         }
1005     }
1006 
1007     /**
1008      * Check if the given Analogue Timer message parameters are valid. Valid parameters should
1009      * adhere to message description of Analogue Timer defined in CEC 1.4 Specification : Message
1010      * Descriptions for Timer Programming Feature (CEC Table 12)
1011      */
1012     private static class AnalogueTimerValidator implements ParameterValidator {
1013         @Override
isValid(byte[] params)1014         public int isValid(byte[] params) {
1015             if (params.length < 11) {
1016                 return ERROR_PARAMETER_SHORT;
1017             }
1018             return toErrorCode(
1019                     isValidDayOfMonth(params[0]) // Day of Month
1020                             && isValidMonthOfYear(params[1]) // Month of Year
1021                             && isValidHour(params[2]) // Start Time - Hour
1022                             && isValidMinute(params[3]) // Start Time - Minute
1023                             && isValidDurationHours(params[4]) // Duration - Duration Hours
1024                             && isValidMinute(params[5]) // Duration - Minute
1025                             && isValidRecordingSequence(params[6]) // Recording Sequence
1026                             && isValidAnalogueBroadcastType(params[7]) // Analogue Broadcast Type
1027                             && isValidAnalogueFrequency(
1028                                     HdmiUtils.twoBytesToInt(params, 8)) // Analogue Frequency
1029                             && isValidBroadcastSystem(params[10])); // Broadcast System
1030         }
1031     }
1032 
1033     /**
1034      * Check if the given Digital Timer message parameters are valid. Valid parameters should adhere
1035      * to message description of Digital Timer defined in CEC 1.4 Specification : Message
1036      * Descriptions for Timer Programming Feature (CEC Table 12)
1037      */
1038     private static class DigitalTimerValidator implements ParameterValidator {
1039         @Override
isValid(byte[] params)1040         public int isValid(byte[] params) {
1041             if (params.length < 11) {
1042                 return ERROR_PARAMETER_SHORT;
1043             }
1044             return toErrorCode(
1045                     isValidDayOfMonth(params[0]) // Day of Month
1046                             && isValidMonthOfYear(params[1]) // Month of Year
1047                             && isValidHour(params[2]) // Start Time - Hour
1048                             && isValidMinute(params[3]) // Start Time - Minute
1049                             && isValidDurationHours(params[4]) // Duration - Duration Hours
1050                             && isValidMinute(params[5]) // Duration - Minute
1051                             && isValidRecordingSequence(params[6]) // Recording Sequence
1052                             && isValidDigitalServiceIdentification(
1053                                     params, 7)); // Digital Service Identification
1054         }
1055     }
1056 
1057     /**
1058      * Check if the given External Timer message parameters are valid. Valid parameters should
1059      * adhere to message description of External Timer defined in CEC 1.4 Specification : Message
1060      * Descriptions for Timer Programming Feature (CEC Table 12)
1061      */
1062     private static class ExternalTimerValidator implements ParameterValidator {
1063         @Override
isValid(byte[] params)1064         public int isValid(byte[] params) {
1065             if (params.length < 9) {
1066                 return ERROR_PARAMETER_SHORT;
1067             }
1068             return toErrorCode(
1069                     isValidDayOfMonth(params[0]) // Day of Month
1070                             && isValidMonthOfYear(params[1]) // Month of Year
1071                             && isValidHour(params[2]) // Start Time - Hour
1072                             && isValidMinute(params[3]) // Start Time - Minute
1073                             && isValidDurationHours(params[4]) // Duration - Duration Hours
1074                             && isValidMinute(params[5]) // Duration - Minute
1075                             && isValidRecordingSequence(params[6]) // Recording Sequence
1076                             && isValidExternalSource(params, 7)); // External Source
1077         }
1078     }
1079 
1080     /**
1081      * Check if the given timer cleared status parameter is valid. A valid parameter should lie
1082      * within the range description defined in CEC 1.4 Specification : Operand Descriptions
1083      * (Section 17)
1084      */
1085     private static class TimerClearedStatusValidator implements ParameterValidator {
1086         @Override
isValid(byte[] params)1087         public int isValid(byte[] params) {
1088             if (params.length < 1) {
1089                 return ERROR_PARAMETER_SHORT;
1090             }
1091             return toErrorCode(isWithinRange(params[0], 0x00, 0x02) || (params[0] & 0xFF) == 0x80);
1092         }
1093     }
1094 
1095     /**
1096      * Check if the given timer status data parameter is valid. A valid parameter should lie within
1097      * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
1098      */
1099     private static class TimerStatusValidator implements ParameterValidator {
1100         @Override
isValid(byte[] params)1101         public int isValid(byte[] params) {
1102             if (params.length < 1) {
1103                 return ERROR_PARAMETER_SHORT;
1104             }
1105             return toErrorCode(isValidTimerStatusData(params, 0));
1106         }
1107     }
1108 
1109     /**
1110      * Check if the given play mode parameter is valid. A valid parameter should lie within the
1111      * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
1112      */
1113     private static class PlayModeValidator implements ParameterValidator {
1114         @Override
isValid(byte[] params)1115         public int isValid(byte[] params) {
1116             if (params.length < 1) {
1117                 return ERROR_PARAMETER_SHORT;
1118             }
1119             return toErrorCode(isValidPlayMode(params[0]));
1120         }
1121     }
1122 
1123     /**
1124      * Check if the given select analogue service parameter is valid. A valid parameter should lie
1125      * within the range description defined in CEC 1.4 Specification : Operand Descriptions
1126      * (Section 17)
1127      */
1128     private static class SelectAnalogueServiceValidator implements ParameterValidator {
1129         @Override
isValid(byte[] params)1130         public int isValid(byte[] params) {
1131             if (params.length < 4) {
1132                 return ERROR_PARAMETER_SHORT;
1133             }
1134             return toErrorCode(isValidAnalogueBroadcastType(params[0])
1135                     && isValidAnalogueFrequency(HdmiUtils.twoBytesToInt(params, 1))
1136                     && isValidBroadcastSystem(params[3]));
1137         }
1138     }
1139 
1140     /**
1141      * Check if the given select digital service parameter is valid. A valid parameter should lie
1142      * within the range description defined in CEC 1.4 Specification : Operand Descriptions
1143      * (Section 17)
1144      */
1145     private static class SelectDigitalServiceValidator implements ParameterValidator {
1146         @Override
isValid(byte[] params)1147         public int isValid(byte[] params) {
1148             if (params.length < 4) {
1149                 return ERROR_PARAMETER_SHORT;
1150             }
1151             return toErrorCode(isValidDigitalServiceIdentification(params, 0));
1152         }
1153     }
1154 
1155     /**
1156      * Check if the given tuner device status parameter is valid. A valid parameter should lie
1157      * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
1158      * 17)
1159      */
1160     private static class TunerDeviceStatusValidator implements ParameterValidator {
1161         @Override
isValid(byte[] params)1162         public int isValid(byte[] params) {
1163             if (params.length < 1) {
1164                 return ERROR_PARAMETER_SHORT;
1165             }
1166             return toErrorCode(isValidTunerDeviceInfo(params));
1167         }
1168     }
1169 
1170     /** Check if the given user control press parameter is valid. */
1171     private static class UserControlPressedValidator implements ParameterValidator {
1172         @Override
isValid(byte[] params)1173         public int isValid(byte[] params) {
1174             if (params.length < 1) {
1175                 return ERROR_PARAMETER_SHORT;
1176             }
1177             if (params.length == 1) {
1178                 return OK;
1179             }
1180             int uiCommand = params[0];
1181             switch (uiCommand) {
1182                 case HdmiCecKeycode.CEC_KEYCODE_PLAY_FUNCTION:
1183                     return toErrorCode(isValidPlayMode(params[1]));
1184                 case HdmiCecKeycode.CEC_KEYCODE_TUNE_FUNCTION:
1185                     return (params.length >= 4
1186                             ? toErrorCode(isValidChannelIdentifier(params, 1))
1187                             : ERROR_PARAMETER_SHORT);
1188                 case HdmiCecKeycode.CEC_KEYCODE_SELECT_BROADCAST_TYPE:
1189                     return toErrorCode(isValidUiBroadcastType(params[1]));
1190                 case HdmiCecKeycode.CEC_KEYCODE_SELECT_SOUND_PRESENTATION:
1191                     return toErrorCode(isValidUiSoundPresenationControl(params[1]));
1192                 default:
1193                     return OK;
1194             }
1195         }
1196     }
1197 }
1198