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 if (physicalAddress == 0xFFFF) { 394 return false; 395 } 396 while (physicalAddress != 0) { 397 int maskedAddress = physicalAddress & 0xF000; 398 physicalAddress = (physicalAddress << 4) & 0xFFFF; 399 if (maskedAddress == 0 && physicalAddress != 0) { 400 return false; 401 } 402 } 403 return true; 404 } 405 406 /** 407 * Check if the given type is valid. A valid type is one of the actual logical device types 408 * defined in the standard ({@link HdmiDeviceInfo#DEVICE_TV}, 409 * {@link HdmiDeviceInfo#DEVICE_PLAYBACK}, {@link HdmiDeviceInfo#DEVICE_TUNER}, 410 * {@link HdmiDeviceInfo#DEVICE_RECORDER}, and {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}). 411 * 412 * @param type device type 413 * @return true if the given type is valid 414 */ isValidType(int type)415 static boolean isValidType(int type) { 416 return (HdmiDeviceInfo.DEVICE_TV <= type 417 && type <= HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR) 418 && type != HdmiDeviceInfo.DEVICE_RESERVED; 419 } 420 toErrorCode(boolean success)421 private static int toErrorCode(boolean success) { 422 return success ? OK : ERROR_PARAMETER; 423 } 424 isWithinRange(int value, int min, int max)425 private static boolean isWithinRange(int value, int min, int max) { 426 value = value & 0xFF; 427 return (value >= min && value <= max); 428 } 429 430 /** 431 * Check if the given value is a valid Display Control. A valid value is one which falls within 432 * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 433 * 434 * @param value Display Control 435 * @return true if the Display Control is valid 436 */ isValidDisplayControl(int value)437 private static boolean isValidDisplayControl(int value) { 438 value = value & 0xFF; 439 return (value == 0x00 || value == 0x40 || value == 0x80 || value == 0xC0); 440 } 441 442 /** 443 * Check if the given params has valid ASCII characters. 444 * A valid ASCII character is a printable character. It should fall within range description 445 * defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 446 * 447 * @param params parameter consisting of string 448 * @param offset Start offset of string 449 * @param maxLength Maximum length of string to be evaluated 450 * @return true if the given type is valid 451 */ isValidAsciiString(byte[] params, int offset, int maxLength)452 private static boolean isValidAsciiString(byte[] params, int offset, int maxLength) { 453 for (int i = offset; i < params.length && i < maxLength; i++) { 454 if (!isWithinRange(params[i], 0x20, 0x7E)) { 455 return false; 456 } 457 } 458 return true; 459 } 460 461 /** 462 * Check if the given value is a valid day of month. A valid value is one which falls within the 463 * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 464 * 465 * @param value day of month 466 * @return true if the day of month is valid 467 */ isValidDayOfMonth(int value)468 private static boolean isValidDayOfMonth(int value) { 469 return isWithinRange(value, 1, 31); 470 } 471 472 /** 473 * Check if the given value is a valid month of year. A valid value is one which falls within 474 * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 475 * 476 * @param value month of year 477 * @return true if the month of year is valid 478 */ isValidMonthOfYear(int value)479 private static boolean isValidMonthOfYear(int value) { 480 return isWithinRange(value, 1, 12); 481 } 482 483 /** 484 * Check if the given value is a valid hour. A valid value is one which falls within the range 485 * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 486 * 487 * @param value hour 488 * @return true if the hour is valid 489 */ isValidHour(int value)490 private static boolean isValidHour(int value) { 491 value = bcdToDecimal(value); 492 return isWithinRange(value, 0, 23); 493 } 494 495 /** 496 * Check if the given value is a valid minute. A valid value is one which falls within the range 497 * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 498 * 499 * @param value minute 500 * @return true if the minute is valid 501 */ isValidMinute(int value)502 private static boolean isValidMinute(int value) { 503 value = bcdToDecimal(value); 504 return isWithinRange(value, 0, 59); 505 } 506 507 /** 508 * Check if the given value is a valid duration hours. A valid value is one which falls within 509 * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 510 * 511 * @param value duration hours 512 * @return true if the duration hours is valid 513 */ isValidDurationHours(int value)514 private static boolean isValidDurationHours(int value) { 515 value = bcdToDecimal(value); 516 return isWithinRange(value, 0, 99); 517 } 518 519 /** 520 * Convert BCD value to decimal value. 521 * 522 * @param value BCD value 523 * @return decimal value 524 */ bcdToDecimal(int value)525 private static int bcdToDecimal(int value) { 526 int tens = (value & 0xF0) >> 4; 527 int ones = (value & 0x0F); 528 529 return tens * 10 + ones; 530 } 531 532 /** 533 * Check if the given value is a valid recording sequence. A valid value is adheres to range 534 * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 535 * 536 * @param value recording sequence 537 * @return true if the given recording sequence is valid 538 */ isValidRecordingSequence(int value)539 private static boolean isValidRecordingSequence(int value) { 540 value = value & 0xFF; 541 // Validate bit 7 is set to zero 542 if ((value & 0x80) != 0x00) { 543 return false; 544 } 545 return true; 546 } 547 548 /** 549 * Check if the given value is a valid analogue broadcast type. A valid value is one which falls 550 * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 551 * 17) 552 * 553 * @param value analogue broadcast type 554 * @return true if the analogue broadcast type is valid 555 */ isValidAnalogueBroadcastType(int value)556 private static boolean isValidAnalogueBroadcastType(int value) { 557 return isWithinRange(value, 0x00, 0x02); 558 } 559 560 /** 561 * Check if the given value is a valid analogue frequency. A valid value is one which falls 562 * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 563 * 17) 564 * 565 * @param value analogue frequency 566 * @return true if the analogue frequency is valid 567 */ isValidAnalogueFrequency(int value)568 private static boolean isValidAnalogueFrequency(int value) { 569 value = value & 0xFFFF; 570 return (value != 0x000 && value != 0xFFFF); 571 } 572 573 /** 574 * Check if the given value is a valid broadcast system. A valid value is one which falls within 575 * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 576 * 577 * @param value broadcast system 578 * @return true if the broadcast system is valid 579 */ isValidBroadcastSystem(int value)580 private static boolean isValidBroadcastSystem(int value) { 581 return isWithinRange(value, 0, 31); 582 } 583 584 /** 585 * Check if the given value is a ARIB type. A valid value is one which falls within the range 586 * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 587 * 588 * @param value Digital Broadcast System 589 * @return true if the Digital Broadcast System is ARIB type 590 */ isAribDbs(int value)591 private static boolean isAribDbs(int value) { 592 return (value == 0x00 || isWithinRange(value, 0x08, 0x0A)); 593 } 594 595 /** 596 * Check if the given value is a ATSC type. A valid value is one which falls within the range 597 * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 598 * 599 * @param value Digital Broadcast System 600 * @return true if the Digital Broadcast System is ATSC type 601 */ isAtscDbs(int value)602 private static boolean isAtscDbs(int value) { 603 return (value == 0x01 || isWithinRange(value, 0x10, 0x12)); 604 } 605 606 /** 607 * Check if the given value is a DVB type. A valid value is one which falls within the range 608 * description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 609 * 610 * @param value Digital Broadcast System 611 * @return true if the Digital Broadcast System is DVB type 612 */ isDvbDbs(int value)613 private static boolean isDvbDbs(int value) { 614 return (value == 0x02 || isWithinRange(value, 0x18, 0x1B)); 615 } 616 617 /** 618 * Check if the given value is a valid Digital Broadcast System. A valid value is one which 619 * falls within the range description defined in CEC 1.4 Specification : Operand Descriptions 620 * (Section 17) 621 * 622 * @param value Digital Broadcast System 623 * @return true if the Digital Broadcast System is valid 624 */ isValidDigitalBroadcastSystem(int value)625 private static boolean isValidDigitalBroadcastSystem(int value) { 626 return (isAribDbs(value) || isAtscDbs(value) || isDvbDbs(value)); 627 } 628 629 /** 630 * Check if the given value is a valid Channel Identifier. A valid value is one which falls 631 * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 632 * 17) 633 * 634 * @param params Channel Identifier parameters 635 * @param offset start offset of Channel Identifier 636 * @return true if the Channel Identifier is valid 637 */ isValidChannelIdentifier(byte[] params, int offset)638 private static boolean isValidChannelIdentifier(byte[] params, int offset) { 639 // First 6 bits contain Channel Number Format 640 int channelNumberFormat = params[offset] & 0xFC; 641 if (channelNumberFormat == 0x04) { 642 // Validate it contains 1-part Channel Number data (16 bits) 643 return params.length - offset >= 3; 644 } else if (channelNumberFormat == 0x08) { 645 // Validate it contains Major Channel Number and Minor Channel Number (26 bits) 646 return params.length - offset >= 4; 647 } 648 return false; 649 } 650 651 /** 652 * Check if the given value is a valid Digital Service Identification. A valid value is one 653 * which falls within the range description defined in CEC 1.4 Specification : Operand 654 * Descriptions (Section 17) 655 * 656 * @param params Digital Timer Message parameters 657 * @param offset start offset of Digital Service Identification 658 * @return true if the Digital Service Identification is valid 659 */ isValidDigitalServiceIdentification(byte[] params, int offset)660 private static boolean isValidDigitalServiceIdentification(byte[] params, int offset) { 661 // MSB contains Service Identification Method 662 int serviceIdentificationMethod = params[offset] & 0x80; 663 // Last 7 bits contains Digital Broadcast System 664 int digitalBroadcastSystem = params[offset] & 0x7F; 665 offset = offset + 1; 666 if (serviceIdentificationMethod == 0x00) { 667 // Services identified by Digital IDs 668 if (isAribDbs(digitalBroadcastSystem)) { 669 // Validate ARIB type have 6 byte data 670 return params.length - offset >= 6; 671 } else if (isAtscDbs(digitalBroadcastSystem)) { 672 // Validate ATSC type have 4 byte data 673 return params.length - offset >= 4; 674 } else if (isDvbDbs(digitalBroadcastSystem)) { 675 // Validate DVB type have 6 byte data 676 return params.length - offset >= 6; 677 } 678 } else if (serviceIdentificationMethod == 0x80) { 679 // Services identified by Channel 680 if (isValidDigitalBroadcastSystem(digitalBroadcastSystem)) { 681 return isValidChannelIdentifier(params, offset); 682 } 683 } 684 return false; 685 } 686 687 /** 688 * Check if the given value is a valid External Plug. A valid value is one which falls within 689 * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 690 * 691 * @param value External Plug 692 * @return true if the External Plug is valid 693 */ isValidExternalPlug(int value)694 private static boolean isValidExternalPlug(int value) { 695 return isWithinRange(value, 1, 255); 696 } 697 698 /** 699 * Check if the given value is a valid External Source. A valid value is one which falls within 700 * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 701 * 702 * @param value External Source Specifier 703 * @return true if the External Source is valid 704 */ isValidExternalSource(byte[] params, int offset)705 private static boolean isValidExternalSource(byte[] params, int offset) { 706 int externalSourceSpecifier = params[offset]; 707 offset = offset + 1; 708 if (externalSourceSpecifier == 0x04) { 709 // External Plug 710 return isValidExternalPlug(params[offset]); 711 } else if (externalSourceSpecifier == 0x05) { 712 // External Physical Address 713 // Validate it contains 2 bytes Physical Address 714 if (params.length - offset >= 2) { 715 return isValidPhysicalAddress(params, offset); 716 } 717 } 718 return false; 719 } 720 isValidProgrammedInfo(int programedInfo)721 private static boolean isValidProgrammedInfo(int programedInfo) { 722 return (isWithinRange(programedInfo, 0x00, 0x0B)); 723 } 724 isValidNotProgrammedErrorInfo(int nonProgramedErrorInfo)725 private static boolean isValidNotProgrammedErrorInfo(int nonProgramedErrorInfo) { 726 return (isWithinRange(nonProgramedErrorInfo, 0x00, 0x0E)); 727 } 728 isValidTimerStatusData(byte[] params, int offset)729 private static boolean isValidTimerStatusData(byte[] params, int offset) { 730 int programedIndicator = params[offset] & 0x10; 731 boolean durationAvailable = false; 732 if (programedIndicator == 0x10) { 733 // Programmed 734 int programedInfo = params[offset] & 0x0F; 735 if (isValidProgrammedInfo(programedInfo)) { 736 offset = offset + 1; 737 // Duration Available (2 bytes) 738 if ((programedInfo == 0x09 || programedInfo == 0x0B) 739 && params.length - offset >= 2) { 740 durationAvailable = true; 741 } else { 742 return true; 743 } 744 } 745 } else { 746 // Non programmed 747 int nonProgramedErrorInfo = params[offset] & 0x0F; 748 if (isValidNotProgrammedErrorInfo(nonProgramedErrorInfo)) { 749 offset = offset + 1; 750 // Duration Available (2 bytes) 751 if (nonProgramedErrorInfo == 0x0E && params.length - offset >= 2) { 752 durationAvailable = true; 753 } else { 754 return true; 755 } 756 } 757 } 758 // Duration Available (2 bytes) 759 if (durationAvailable) { 760 return (isValidDurationHours(params[offset]) && isValidMinute(params[offset + 1])); 761 } 762 return false; 763 } 764 765 /** 766 * Check if the given value is a valid Play mode. A valid value is one which falls within the 767 * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 768 * 769 * @param value Play mode 770 * @return true if the Play mode is valid 771 */ isValidPlayMode(int value)772 private static boolean isValidPlayMode(int value) { 773 return (isWithinRange(value, 0x05, 0x07) 774 || isWithinRange(value, 0x09, 0x0B) 775 || isWithinRange(value, 0x15, 0x17) 776 || isWithinRange(value, 0x19, 0x1B) 777 || isWithinRange(value, 0x24, 0x25) 778 || (value == 0x20)); 779 } 780 781 /** 782 * Check if the given value is a valid UI Broadcast type. A valid value is one which falls 783 * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 784 * 17) 785 * 786 * @param value UI Broadcast type 787 * @return true if the UI Broadcast type is valid 788 */ isValidUiBroadcastType(int value)789 private static boolean isValidUiBroadcastType(int value) { 790 value = value & 0xFF; 791 return ((value == 0x00) 792 || (value == 0x01) 793 || (value == 0x10) 794 || (value == 0x20) 795 || (value == 0x30) 796 || (value == 0x40) 797 || (value == 0x50) 798 || (value == 0x60) 799 || (value == 0x70) 800 || (value == 0x80) 801 || (value == 0x90) 802 || (value == 0x91) 803 || (value == 0xA0)); 804 } 805 806 /** 807 * Check if the given value is a valid UI Sound Presenation Control. A valid value is one which 808 * falls within the range description defined in CEC 1.4 Specification : Operand Descriptions 809 * (Section 17) 810 * 811 * @param value UI Sound Presenation Control 812 * @return true if the UI Sound Presenation Control is valid 813 */ isValidUiSoundPresenationControl(int value)814 private static boolean isValidUiSoundPresenationControl(int value) { 815 value = value & 0xFF; 816 return ((value == 0x20) 817 || (value == 0x30) 818 || (value == 0x80) 819 || (value == 0x90) 820 || (value == 0xA0) 821 || (isWithinRange(value, 0xB1, 0xB3)) 822 || (isWithinRange(value, 0xC1, 0xC3))); 823 } 824 825 /* 826 * Check if the given value is a valid Tuner Device info. A valid value is one which falls 827 * within the range description defined in CEC 1.4 Specification : Operand Descriptions 828 * (Section 17) 829 * 830 * @param params Tuner device info 831 * @return true if the Tuner device info is valid 832 */ isValidTunerDeviceInfo(byte[] params)833 private static boolean isValidTunerDeviceInfo(byte[] params) { 834 int tunerDisplayInfo = params[0] & 0x7F; 835 if (tunerDisplayInfo == 0x00) { 836 // Displaying digital tuner 837 if (params.length >= 5) { 838 return isValidDigitalServiceIdentification(params, 1); 839 } 840 } else if (tunerDisplayInfo == 0x01) { 841 // Not displaying Tuner 842 return true; 843 } else if (tunerDisplayInfo == 0x02) { 844 // Displaying Analogue tuner 845 if (params.length >= 5) { 846 return (isValidAnalogueBroadcastType(params[1]) 847 && isValidAnalogueFrequency(HdmiUtils.twoBytesToInt(params, 2)) 848 && isValidBroadcastSystem(params[4])); 849 } 850 } 851 return false; 852 } 853 854 private static class PhysicalAddressValidator implements ParameterValidator { 855 @Override isValid(byte[] params)856 public int isValid(byte[] params) { 857 if (params.length < 2) { 858 return ERROR_PARAMETER_SHORT; 859 } 860 return toErrorCode(isValidPhysicalAddress(params, 0)); 861 } 862 } 863 864 private static class SystemAudioModeRequestValidator extends PhysicalAddressValidator { 865 @Override isValid(byte[] params)866 public int isValid(byte[] params) { 867 // TV can send <System Audio Mode Request> with no parameters to terminate system audio. 868 if (params.length == 0) { 869 return OK; 870 } 871 return super.isValid(params); 872 } 873 } 874 875 private static class ReportPhysicalAddressValidator implements ParameterValidator { 876 @Override isValid(byte[] params)877 public int isValid(byte[] params) { 878 if (params.length < 3) { 879 return ERROR_PARAMETER_SHORT; 880 } 881 return toErrorCode(isValidPhysicalAddress(params, 0) && isValidType(params[2])); 882 } 883 } 884 885 private static class RoutingChangeValidator implements ParameterValidator { 886 @Override isValid(byte[] params)887 public int isValid(byte[] params) { 888 if (params.length < 4) { 889 return ERROR_PARAMETER_SHORT; 890 } 891 return toErrorCode( 892 isValidPhysicalAddress(params, 0) && isValidPhysicalAddress(params, 2)); 893 } 894 } 895 896 /** 897 * Check if the given record status message parameter is valid. 898 * A valid parameter should lie within the range description of Record Status Info defined in 899 * CEC 1.4 Specification : Operand Descriptions (Section 17) 900 */ 901 private static class RecordStatusInfoValidator implements ParameterValidator { 902 @Override isValid(byte[] params)903 public int isValid(byte[] params) { 904 if (params.length < 1) { 905 return ERROR_PARAMETER_SHORT; 906 } 907 return toErrorCode(isWithinRange(params[0], 0x01, 0x07) 908 || isWithinRange(params[0], 0x09, 0x0E) 909 || isWithinRange(params[0], 0x10, 0x17) 910 || isWithinRange(params[0], 0x1A, 0x1B) 911 || params[0] == 0x1F); 912 } 913 } 914 915 /** 916 * Check if the given parameters represents printable characters. 917 * A valid parameter should lie within the range description of ASCII defined in CEC 1.4 918 * Specification : Operand Descriptions (Section 17) 919 */ 920 private static class AsciiValidator implements ParameterValidator { 921 private final int mMinLength; 922 private final int mMaxLength; 923 AsciiValidator(int length)924 AsciiValidator(int length) { 925 mMinLength = length; 926 mMaxLength = length; 927 } 928 AsciiValidator(int minLength, int maxLength)929 AsciiValidator(int minLength, int maxLength) { 930 mMinLength = minLength; 931 mMaxLength = maxLength; 932 } 933 934 @Override isValid(byte[] params)935 public int isValid(byte[] params) { 936 // If the length is longer than expected, we assume it's OK since the parameter can be 937 // extended in the future version. 938 if (params.length < mMinLength) { 939 return ERROR_PARAMETER_SHORT; 940 } 941 return toErrorCode(isValidAsciiString(params, 0, mMaxLength)); 942 } 943 } 944 945 /** 946 * Check if the given parameters is valid OSD String. 947 * A valid parameter should lie within the range description of ASCII defined in CEC 1.4 948 * Specification : Operand Descriptions (Section 17) 949 */ 950 private static class OsdStringValidator implements ParameterValidator { 951 @Override isValid(byte[] params)952 public int isValid(byte[] params) { 953 // If the length is longer than expected, we assume it's OK since the parameter can be 954 // extended in the future version. 955 if (params.length < 2) { 956 return ERROR_PARAMETER_SHORT; 957 } 958 return toErrorCode( 959 // Display Control 960 isValidDisplayControl(params[0]) 961 // OSD String 962 && isValidAsciiString(params, 1, 14)); 963 } 964 } 965 966 /** 967 * Check if the given parameters are at least one byte parameters 968 * and the first byte is within range. 969 */ 970 private static class MinimumOneByteRangeValidator implements ParameterValidator { 971 private final int mMinValue, mMaxValue; 972 MinimumOneByteRangeValidator(int minValue, int maxValue)973 MinimumOneByteRangeValidator(int minValue, int maxValue) { 974 mMinValue = minValue; 975 mMaxValue = maxValue; 976 } 977 978 @Override isValid(byte[] params)979 public int isValid(byte[] params) { 980 if (params.length < 1) { 981 return ERROR_PARAMETER_SHORT; 982 } 983 return toErrorCode(isWithinRange(params[0], mMinValue, mMaxValue)); 984 } 985 } 986 987 /** Check if the given parameters are exactly one byte parameters and within range. */ 988 private static class SingleByteRangeValidator implements ParameterValidator { 989 private final int mMinValue, mMaxValue; 990 SingleByteRangeValidator(int minValue, int maxValue)991 SingleByteRangeValidator(int minValue, int maxValue) { 992 mMinValue = minValue; 993 mMaxValue = maxValue; 994 } 995 996 @Override isValid(byte[] params)997 public int isValid(byte[] params) { 998 if (params.length < 1) { 999 return ERROR_PARAMETER_SHORT; 1000 } else if (params.length > 1) { 1001 return ERROR_PARAMETER_LONG; 1002 } 1003 return toErrorCode(isWithinRange(params[0], mMinValue, mMaxValue)); 1004 } 1005 } 1006 1007 /** 1008 * Check if the given Analogue Timer message parameters are valid. Valid parameters should 1009 * adhere to message description of Analogue Timer defined in CEC 1.4 Specification : Message 1010 * Descriptions for Timer Programming Feature (CEC Table 12) 1011 */ 1012 private static class AnalogueTimerValidator implements ParameterValidator { 1013 @Override isValid(byte[] params)1014 public int isValid(byte[] params) { 1015 if (params.length < 11) { 1016 return ERROR_PARAMETER_SHORT; 1017 } 1018 return toErrorCode( 1019 isValidDayOfMonth(params[0]) // Day of Month 1020 && isValidMonthOfYear(params[1]) // Month of Year 1021 && isValidHour(params[2]) // Start Time - Hour 1022 && isValidMinute(params[3]) // Start Time - Minute 1023 && isValidDurationHours(params[4]) // Duration - Duration Hours 1024 && isValidMinute(params[5]) // Duration - Minute 1025 && isValidRecordingSequence(params[6]) // Recording Sequence 1026 && isValidAnalogueBroadcastType(params[7]) // Analogue Broadcast Type 1027 && isValidAnalogueFrequency( 1028 HdmiUtils.twoBytesToInt(params, 8)) // Analogue Frequency 1029 && isValidBroadcastSystem(params[10])); // Broadcast System 1030 } 1031 } 1032 1033 /** 1034 * Check if the given Digital Timer message parameters are valid. Valid parameters should adhere 1035 * to message description of Digital Timer defined in CEC 1.4 Specification : Message 1036 * Descriptions for Timer Programming Feature (CEC Table 12) 1037 */ 1038 private static class DigitalTimerValidator implements ParameterValidator { 1039 @Override isValid(byte[] params)1040 public int isValid(byte[] params) { 1041 if (params.length < 11) { 1042 return ERROR_PARAMETER_SHORT; 1043 } 1044 return toErrorCode( 1045 isValidDayOfMonth(params[0]) // Day of Month 1046 && isValidMonthOfYear(params[1]) // Month of Year 1047 && isValidHour(params[2]) // Start Time - Hour 1048 && isValidMinute(params[3]) // Start Time - Minute 1049 && isValidDurationHours(params[4]) // Duration - Duration Hours 1050 && isValidMinute(params[5]) // Duration - Minute 1051 && isValidRecordingSequence(params[6]) // Recording Sequence 1052 && isValidDigitalServiceIdentification( 1053 params, 7)); // Digital Service Identification 1054 } 1055 } 1056 1057 /** 1058 * Check if the given External Timer message parameters are valid. Valid parameters should 1059 * adhere to message description of External Timer defined in CEC 1.4 Specification : Message 1060 * Descriptions for Timer Programming Feature (CEC Table 12) 1061 */ 1062 private static class ExternalTimerValidator implements ParameterValidator { 1063 @Override isValid(byte[] params)1064 public int isValid(byte[] params) { 1065 if (params.length < 9) { 1066 return ERROR_PARAMETER_SHORT; 1067 } 1068 return toErrorCode( 1069 isValidDayOfMonth(params[0]) // Day of Month 1070 && isValidMonthOfYear(params[1]) // Month of Year 1071 && isValidHour(params[2]) // Start Time - Hour 1072 && isValidMinute(params[3]) // Start Time - Minute 1073 && isValidDurationHours(params[4]) // Duration - Duration Hours 1074 && isValidMinute(params[5]) // Duration - Minute 1075 && isValidRecordingSequence(params[6]) // Recording Sequence 1076 && isValidExternalSource(params, 7)); // External Source 1077 } 1078 } 1079 1080 /** 1081 * Check if the given timer cleared status parameter is valid. A valid parameter should lie 1082 * within the range description defined in CEC 1.4 Specification : Operand Descriptions 1083 * (Section 17) 1084 */ 1085 private static class TimerClearedStatusValidator implements ParameterValidator { 1086 @Override isValid(byte[] params)1087 public int isValid(byte[] params) { 1088 if (params.length < 1) { 1089 return ERROR_PARAMETER_SHORT; 1090 } 1091 return toErrorCode(isWithinRange(params[0], 0x00, 0x02) || (params[0] & 0xFF) == 0x80); 1092 } 1093 } 1094 1095 /** 1096 * Check if the given timer status data parameter is valid. A valid parameter should lie within 1097 * the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 1098 */ 1099 private static class TimerStatusValidator implements ParameterValidator { 1100 @Override isValid(byte[] params)1101 public int isValid(byte[] params) { 1102 if (params.length < 1) { 1103 return ERROR_PARAMETER_SHORT; 1104 } 1105 return toErrorCode(isValidTimerStatusData(params, 0)); 1106 } 1107 } 1108 1109 /** 1110 * Check if the given play mode parameter is valid. A valid parameter should lie within the 1111 * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17) 1112 */ 1113 private static class PlayModeValidator implements ParameterValidator { 1114 @Override isValid(byte[] params)1115 public int isValid(byte[] params) { 1116 if (params.length < 1) { 1117 return ERROR_PARAMETER_SHORT; 1118 } 1119 return toErrorCode(isValidPlayMode(params[0])); 1120 } 1121 } 1122 1123 /** 1124 * Check if the given select analogue service parameter is valid. A valid parameter should lie 1125 * within the range description defined in CEC 1.4 Specification : Operand Descriptions 1126 * (Section 17) 1127 */ 1128 private static class SelectAnalogueServiceValidator implements ParameterValidator { 1129 @Override isValid(byte[] params)1130 public int isValid(byte[] params) { 1131 if (params.length < 4) { 1132 return ERROR_PARAMETER_SHORT; 1133 } 1134 return toErrorCode(isValidAnalogueBroadcastType(params[0]) 1135 && isValidAnalogueFrequency(HdmiUtils.twoBytesToInt(params, 1)) 1136 && isValidBroadcastSystem(params[3])); 1137 } 1138 } 1139 1140 /** 1141 * Check if the given select digital service parameter is valid. A valid parameter should lie 1142 * within the range description defined in CEC 1.4 Specification : Operand Descriptions 1143 * (Section 17) 1144 */ 1145 private static class SelectDigitalServiceValidator implements ParameterValidator { 1146 @Override isValid(byte[] params)1147 public int isValid(byte[] params) { 1148 if (params.length < 4) { 1149 return ERROR_PARAMETER_SHORT; 1150 } 1151 return toErrorCode(isValidDigitalServiceIdentification(params, 0)); 1152 } 1153 } 1154 1155 /** 1156 * Check if the given tuner device status parameter is valid. A valid parameter should lie 1157 * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section 1158 * 17) 1159 */ 1160 private static class TunerDeviceStatusValidator implements ParameterValidator { 1161 @Override isValid(byte[] params)1162 public int isValid(byte[] params) { 1163 if (params.length < 1) { 1164 return ERROR_PARAMETER_SHORT; 1165 } 1166 return toErrorCode(isValidTunerDeviceInfo(params)); 1167 } 1168 } 1169 1170 /** Check if the given user control press parameter is valid. */ 1171 private static class UserControlPressedValidator implements ParameterValidator { 1172 @Override isValid(byte[] params)1173 public int isValid(byte[] params) { 1174 if (params.length < 1) { 1175 return ERROR_PARAMETER_SHORT; 1176 } 1177 if (params.length == 1) { 1178 return OK; 1179 } 1180 int uiCommand = params[0]; 1181 switch (uiCommand) { 1182 case HdmiCecKeycode.CEC_KEYCODE_PLAY_FUNCTION: 1183 return toErrorCode(isValidPlayMode(params[1])); 1184 case HdmiCecKeycode.CEC_KEYCODE_TUNE_FUNCTION: 1185 return (params.length >= 4 1186 ? toErrorCode(isValidChannelIdentifier(params, 1)) 1187 : ERROR_PARAMETER_SHORT); 1188 case HdmiCecKeycode.CEC_KEYCODE_SELECT_BROADCAST_TYPE: 1189 return toErrorCode(isValidUiBroadcastType(params[1])); 1190 case HdmiCecKeycode.CEC_KEYCODE_SELECT_SOUND_PRESENTATION: 1191 return toErrorCode(isValidUiSoundPresenationControl(params[1])); 1192 default: 1193 return OK; 1194 } 1195 } 1196 } 1197 } 1198