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