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