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