175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo/* 275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * Copyright (C) 2014 The Android Open Source Project 375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * 475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * Licensed under the Apache License, Version 2.0 (the "License"); 575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * you may not use this file except in compliance with the License. 675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * You may obtain a copy of the License at 775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * 875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * http://www.apache.org/licenses/LICENSE-2.0 975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * 1075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * Unless required by applicable law or agreed to in writing, software 1175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * distributed under the License is distributed on an "AS IS" BASIS, 1275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * See the License for the specific language governing permissions and 1475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * limitations under the License. 1575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo */ 1675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 1775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heopackage com.android.server.hdmi; 1875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 1961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 2075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heoimport android.util.SparseArray; 2175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 2275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo/** 2375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * A helper class to validates {@link HdmiCecMessage}. 2475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo */ 2575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heopublic final class HdmiCecMessageValidator { 2675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private static final String TAG = "HdmiCecMessageValidator"; 2775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 284c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo static final int OK = 0; 294c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo static final int ERROR_SOURCE = 1; 304c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo static final int ERROR_DESTINATION = 2; 314c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo static final int ERROR_PARAMETER = 3; 32a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo static final int ERROR_PARAMETER_SHORT = 4; 334c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo 3475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private final HdmiControlService mService; 3575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 3675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo interface ParameterValidator { 37a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo /** 38a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo * @return errorCode errorCode can be {@link #OK}, {@link #ERROR_PARAMETER} or 39a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo * {@link #ERROR_PARAMETER_SHORT}. 40a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo */ 41a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo int isValid(byte[] params); 4275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 4375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 44e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // Only the direct addressing is allowed. 45e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo private static final int DEST_DIRECT = 1 << 0; 46e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // Only the broadcast addressing is allowed. 47e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo private static final int DEST_BROADCAST = 1 << 1; 48e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // Both the direct and the broadcast addressing are allowed. 49e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo private static final int DEST_ALL = DEST_DIRECT | DEST_BROADCAST; 50e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // True if the messages from address 15 (unregistered) are allowed. 51e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo private static final int SRC_UNREGISTERED = 1 << 2; 52e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo 53e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo private static class ValidationInfo { 54e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo public final ParameterValidator parameterValidator; 55e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo public final int addressType; 56e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo 57e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo public ValidationInfo(ParameterValidator validator, int type) { 58e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo parameterValidator = validator; 59e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addressType = type; 60e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } 61e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } 62e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo 63e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo final SparseArray<ValidationInfo> mValidationInfo = new SparseArray<>(); 6475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 6575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo public HdmiCecMessageValidator(HdmiControlService service) { 6675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mService = service; 6775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 6875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages related to the physical address. 6975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo PhysicalAddressValidator physicalAddressValidator = new PhysicalAddressValidator(); 70e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_ACTIVE_SOURCE, 71e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo physicalAddressValidator, DEST_BROADCAST | SRC_UNREGISTERED); 72e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_INACTIVE_SOURCE, physicalAddressValidator, DEST_DIRECT); 73e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, 74e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo new ReportPhysicalAddressValidator(), DEST_BROADCAST | SRC_UNREGISTERED); 75e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_ROUTING_CHANGE, 76e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo new RoutingChangeValidator(), DEST_BROADCAST | SRC_UNREGISTERED); 77e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_ROUTING_INFORMATION, 78e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo physicalAddressValidator, DEST_BROADCAST | SRC_UNREGISTERED); 79e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_SET_STREAM_PATH, 80e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo physicalAddressValidator, DEST_BROADCAST); 81e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST, 8203611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo new SystemAudioModeRequestValidator(), DEST_DIRECT); 8375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 8475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages have no parameter. 8575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo FixedLengthValidator noneValidator = new FixedLengthValidator(0); 86e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_ABORT, noneValidator, DEST_DIRECT); 87e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_GET_CEC_VERSION, noneValidator, DEST_DIRECT); 88e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_GET_MENU_LANGUAGE, 89e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo noneValidator, DEST_DIRECT | SRC_UNREGISTERED); 90e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_GIVE_AUDIO_STATUS, noneValidator, DEST_DIRECT); 91e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, noneValidator, DEST_DIRECT); 92e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, 93e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo noneValidator, DEST_DIRECT | SRC_UNREGISTERED); 94e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_GIVE_OSD_NAME, noneValidator, DEST_DIRECT); 95e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, 96e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo noneValidator, DEST_DIRECT | SRC_UNREGISTERED); 97e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS, 98e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo noneValidator, DEST_DIRECT); 99e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_IMAGE_VIEW_ON, noneValidator, DEST_DIRECT); 100e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_INITIATE_ARC, noneValidator, DEST_DIRECT); 101e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_RECORD_OFF, noneValidator, DEST_DIRECT); 102e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_RECORD_TV_SCREEN, noneValidator, DEST_DIRECT); 103e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REPORT_ARC_INITIATED, noneValidator, DEST_DIRECT); 104e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REPORT_ARC_TERMINATED, noneValidator, DEST_DIRECT); 105e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REQUEST_ARC_INITIATION, noneValidator, DEST_DIRECT); 106e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REQUEST_ARC_TERMINATION, noneValidator, DEST_DIRECT); 107e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, 108e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo noneValidator, DEST_BROADCAST | SRC_UNREGISTERED); 109e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_STANDBY, noneValidator, DEST_ALL | SRC_UNREGISTERED); 110e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_TERMINATE_ARC, noneValidator, DEST_DIRECT); 111e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_TEXT_VIEW_ON, noneValidator, DEST_DIRECT); 112e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_TUNER_STEP_DECREMENT, noneValidator, DEST_DIRECT); 113e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_TUNER_STEP_INCREMENT, noneValidator, DEST_DIRECT); 114e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_USER_CONTROL_RELEASED, noneValidator, DEST_DIRECT); 115e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP, noneValidator, DEST_ALL); 11675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 11775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // TODO: Validate more than length for the following messages. 11875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 11975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the One Touch Record. 12075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo FixedLengthValidator oneByteValidator = new FixedLengthValidator(1); 121e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_RECORD_ON, 122e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo new VariableLengthValidator(1, 8), DEST_DIRECT); 123e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_RECORD_STATUS, oneByteValidator, DEST_DIRECT); 12475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 12575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // TODO: Handle messages for the Timer Programming. 12675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 12775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the System Information. 128e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_CEC_VERSION, oneByteValidator, DEST_DIRECT); 129e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE, 130e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo new FixedLengthValidator(3), DEST_BROADCAST); 13175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 13275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // TODO: Handle messages for the Deck Control. 13375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 13475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // TODO: Handle messages for the Tuner Control. 13575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 13675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the Vendor Specific Commands. 13775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo VariableLengthValidator maxLengthValidator = new VariableLengthValidator(0, 14); 138e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_DEVICE_VENDOR_ID, 139e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo new FixedLengthValidator(3), DEST_BROADCAST); 140e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // Allow unregistered source for all vendor specific commands, because we don't know 141e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // how to use the commands at this moment. 142e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_VENDOR_COMMAND, 143e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo maxLengthValidator, DEST_DIRECT | SRC_UNREGISTERED); 144e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, 145a95794bc4fbc5cd19561e447535b99bbae00de25Jinsuk Kim new VariableLengthValidator(4, 14), DEST_ALL | SRC_UNREGISTERED); 146e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN, 147e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo maxLengthValidator, DEST_ALL | SRC_UNREGISTERED); 14875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 14975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the OSD. 150e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_SET_OSD_STRING, maxLengthValidator, DEST_DIRECT); 151e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_SET_OSD_NAME, maxLengthValidator, DEST_DIRECT); 15275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 153184b124ec22a796327642e3546d366179e693f07Yuncheol Heo // Messages for the Device Menu Control. 154184b124ec22a796327642e3546d366179e693f07Yuncheol Heo addValidationInfo(Constants.MESSAGE_MENU_REQUEST, oneByteValidator, DEST_DIRECT); 155184b124ec22a796327642e3546d366179e693f07Yuncheol Heo addValidationInfo(Constants.MESSAGE_MENU_STATUS, oneByteValidator, DEST_DIRECT); 15675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 15775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the Remote Control Passthrough. 15875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // TODO: Parse the first parameter and determine if it can have the next parameter. 159e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_USER_CONTROL_PRESSED, 160e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo new VariableLengthValidator(1, 2), DEST_DIRECT); 16175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 16275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the Power Status. 163e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REPORT_POWER_STATUS, oneByteValidator, DEST_DIRECT); 16475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 16575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the General Protocol. 166e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_FEATURE_ABORT, 167e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo new FixedLengthValidator(2), DEST_DIRECT); 16875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 16975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the System Audio Control. 170e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REPORT_AUDIO_STATUS, oneByteValidator, DEST_DIRECT); 171e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, 172e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo new FixedLengthValidator(3), DEST_DIRECT); 173e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, 174e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo oneByteValidator, DEST_DIRECT); 175e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, oneByteValidator, DEST_ALL); 176e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, 177e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo oneByteValidator, DEST_DIRECT); 17875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 17975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the Audio Rate Control. 180e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_SET_AUDIO_RATE, oneByteValidator, DEST_DIRECT); 18175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 18275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // All Messages for the ARC have no parameters. 18375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 18475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo // Messages for the Capability Discovery and Control. 185e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo addValidationInfo(Constants.MESSAGE_CDC_MESSAGE, maxLengthValidator, 186e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo DEST_BROADCAST | SRC_UNREGISTERED); 187e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } 188e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo 189e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo private void addValidationInfo(int opcode, ParameterValidator validator, int addrType) { 190e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo mValidationInfo.append(opcode, new ValidationInfo(validator, addrType)); 19175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 19275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 1934c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo int isValid(HdmiCecMessage message) { 19475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo int opcode = message.getOpcode(); 195e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo ValidationInfo info = mValidationInfo.get(opcode); 196e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo if (info == null) { 1972e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("No validation information for the message: " + message); 1984c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return OK; 19975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 200e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo 201e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // Check the source field. 202e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo if (message.getSource() == Constants.ADDR_UNREGISTERED && 203e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo (info.addressType & SRC_UNREGISTERED) == 0) { 2042e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unexpected source: " + message); 2054c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return ERROR_SOURCE; 206e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } 207e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // Check the destination field. 208e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo if (message.getDestination() == Constants.ADDR_BROADCAST) { 209e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo if ((info.addressType & DEST_BROADCAST) == 0) { 2102e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unexpected broadcast message: " + message); 2114c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return ERROR_DESTINATION; 212e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } 213e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } else { // Direct addressing. 214e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo if ((info.addressType & DEST_DIRECT) == 0) { 2152e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unexpected direct message: " + message); 2164c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return ERROR_DESTINATION; 217e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } 218e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } 219e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo 220e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo // Check the parameter type. 221a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo int errorCode = info.parameterValidator.isValid(message.getParams()); 222a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo if (errorCode != OK) { 2232e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unexpected parameters: " + message); 224a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return errorCode; 225e9b9b1e7845d93015363c627d76b719f33120158Yuncheol Heo } 2264c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return OK; 22775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 22875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 22975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private static class FixedLengthValidator implements ParameterValidator { 23075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private final int mLength; 23175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 23275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo public FixedLengthValidator(int length) { 23375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mLength = length; 23475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 23575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 23675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo @Override 237a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo public int isValid(byte[] params) { 238a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // If the length is longer than expected, we assume it's OK since the parameter can be 239a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // extended in the future version. 240a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return params.length < mLength ? ERROR_PARAMETER_SHORT : OK; 24175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 24275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 24375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 24475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private static class VariableLengthValidator implements ParameterValidator { 24575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private final int mMinLength; 24675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private final int mMaxLength; 24775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 24875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo public VariableLengthValidator(int minLength, int maxLength) { 24975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMinLength = minLength; 25075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMaxLength = maxLength; 25175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 25275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 25375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo @Override 254a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo public int isValid(byte[] params) { 255a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return params.length < mMinLength ? ERROR_PARAMETER_SHORT : OK; 25675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 25775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 25875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 25975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private boolean isValidPhysicalAddress(byte[] params, int offset) { 260e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo // TODO: Add more logic like validating 1.0.1.0. 261e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 262e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo if (!mService.isTvDevice()) { 263e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo // If the device is not TV, we can't convert path to port-id, so stop here. 264e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo return true; 265e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 26675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo int path = HdmiUtils.twoBytesToInt(params, offset); 2677dea98f6f929cce598d669a802b13851987e2e64Yuncheol Heo if (path != Constants.INVALID_PHYSICAL_ADDRESS && path == mService.getPhysicalAddress()) { 2687dea98f6f929cce598d669a802b13851987e2e64Yuncheol Heo return true; 2697dea98f6f929cce598d669a802b13851987e2e64Yuncheol Heo } 27075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo int portId = mService.pathToPortId(path); 27175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo if (portId == Constants.INVALID_PORT_ID) { 27275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return false; 27375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 27475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return true; 27575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 27675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 27775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo /** 2788e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang * Check if the given type is valid. A valid type is one of the actual logical device types 2797dea98f6f929cce598d669a802b13851987e2e64Yuncheol Heo * defined in the standard ({@link HdmiDeviceInfo#DEVICE_TV}, 2807dea98f6f929cce598d669a802b13851987e2e64Yuncheol Heo * {@link HdmiDeviceInfo#DEVICE_PLAYBACK}, {@link HdmiDeviceInfo#DEVICE_TUNER}, 281a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo * {@link HdmiDeviceInfo#DEVICE_RECORDER}, and {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}). 28275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * 28375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * @param type device type 28475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo * @return true if the given type is valid 28575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo */ 28675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo static boolean isValidType(int type) { 28761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiDeviceInfo.DEVICE_TV <= type 28861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang && type <= HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR) 28961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang && type != HdmiDeviceInfo.DEVICE_RESERVED; 29075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 29175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 292a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo private static int toErrorCode(boolean success) { 293a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return success ? OK : ERROR_PARAMETER; 294a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo } 295a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo 29675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private class PhysicalAddressValidator implements ParameterValidator { 29775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo @Override 298a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo public int isValid(byte[] params) { 299a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo if (params.length < 2) { 300a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return ERROR_PARAMETER_SHORT; 30175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 302a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return toErrorCode(isValidPhysicalAddress(params, 0)); 30375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 30475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 30575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 30603611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo private class SystemAudioModeRequestValidator extends PhysicalAddressValidator { 30703611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo @Override 30803611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo public int isValid(byte[] params) { 30903611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo // TV can send <System Audio Mode Request> with no parameters to terminate system audio. 31003611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo if (params.length == 0) { 31103611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo return OK; 31203611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo } 31303611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo return super.isValid(params); 31403611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo } 31503611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo } 31603611473bc1d13f8e55ac92e37a9716c2fd8e412Yuncheol Heo 31775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private class ReportPhysicalAddressValidator implements ParameterValidator { 31875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo @Override 319a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo public int isValid(byte[] params) { 320a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo if (params.length < 3) { 321a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return ERROR_PARAMETER_SHORT; 32275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 323a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return toErrorCode(isValidPhysicalAddress(params, 0) && isValidType(params[2])); 32475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 32575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 32675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 32775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private class RoutingChangeValidator implements ParameterValidator { 32875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo @Override 329a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo public int isValid(byte[] params) { 330a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo if (params.length < 4) { 331a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return ERROR_PARAMETER_SHORT; 33275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 333a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo return toErrorCode( 334a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo isValidPhysicalAddress(params, 0) && isValidPhysicalAddress(params, 2)); 33575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 33675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 33775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo} 338