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