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