HdmiCecMessageValidator.java revision 75a77e7d6cbfc287c6126efd28b338b48b7ea70c
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 17package com.android.server.hdmi; 18 19import android.hardware.hdmi.HdmiCecDeviceInfo; 20import android.util.Slog; 21import android.util.SparseArray; 22 23/** 24 * A helper class to validates {@link HdmiCecMessage}. 25 */ 26public final class HdmiCecMessageValidator { 27 private static final String TAG = "HdmiCecMessageValidator"; 28 29 private final HdmiControlService mService; 30 31 interface ParameterValidator { 32 boolean isValid(byte[] params); 33 } 34 35 final SparseArray<ParameterValidator> mValidators = new SparseArray<>(); 36 37 public HdmiCecMessageValidator(HdmiControlService service) { 38 mService = service; 39 40 // Messages related to the physical address. 41 PhysicalAddressValidator physicalAddressValidator = new PhysicalAddressValidator(); 42 mValidators.append(Constants.MESSAGE_ACTIVE_SOURCE, physicalAddressValidator); 43 mValidators.append(Constants.MESSAGE_INACTIVE_SOURCE, physicalAddressValidator); 44 mValidators.append(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, 45 new ReportPhysicalAddressValidator()); 46 mValidators.append(Constants.MESSAGE_ROUTING_CHANGE, new RoutingChangeValidator()); 47 mValidators.append(Constants.MESSAGE_ROUTING_INFORMATION, physicalAddressValidator); 48 mValidators.append(Constants.MESSAGE_SET_STREAM_PATH, physicalAddressValidator); 49 mValidators.append(Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST, physicalAddressValidator); 50 51 // Messages have no parameter. 52 FixedLengthValidator noneValidator = new FixedLengthValidator(0); 53 mValidators.append(Constants.MESSAGE_ABORT, noneValidator); 54 mValidators.append(Constants.MESSAGE_GET_CEC_VERSION, noneValidator); 55 mValidators.append(Constants.MESSAGE_GET_MENU_LANGUAGE, noneValidator); 56 mValidators.append(Constants.MESSAGE_GIVE_AUDIO_STATUS, noneValidator); 57 mValidators.append(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, noneValidator); 58 mValidators.append(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, noneValidator); 59 mValidators.append(Constants.MESSAGE_GIVE_OSD_NAME, noneValidator); 60 mValidators.append(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, noneValidator); 61 mValidators.append(Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS, noneValidator); 62 mValidators.append(Constants.MESSAGE_IMAGE_VIEW_ON, noneValidator); 63 mValidators.append(Constants.MESSAGE_INITIATE_ARC, noneValidator); 64 mValidators.append(Constants.MESSAGE_RECORD_OFF, noneValidator); 65 mValidators.append(Constants.MESSAGE_RECORD_TV_SCREEN, noneValidator); 66 mValidators.append(Constants.MESSAGE_REPORT_ARC_INITIATED, noneValidator); 67 mValidators.append(Constants.MESSAGE_REPORT_ARC_TERMINATED, noneValidator); 68 mValidators.append(Constants.MESSAGE_REQUEST_ARC_INITIATION, noneValidator); 69 mValidators.append(Constants.MESSAGE_REQUEST_ARC_TERMINATION, noneValidator); 70 mValidators.append(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, noneValidator); 71 mValidators.append(Constants.MESSAGE_STANDBY, noneValidator); 72 mValidators.append(Constants.MESSAGE_TERMINATE_ARC, noneValidator); 73 mValidators.append(Constants.MESSAGE_TEXT_VIEW_ON, noneValidator); 74 mValidators.append(Constants.MESSAGE_TUNER_STEP_DECREMENT, noneValidator); 75 mValidators.append(Constants.MESSAGE_TUNER_STEP_INCREMENT, noneValidator); 76 mValidators.append(Constants.MESSAGE_USER_CONTROL_RELEASED, noneValidator); 77 mValidators.append(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP, noneValidator); 78 79 // TODO: Validate more than length for the following messages. 80 81 // Messages for the One Touch Record. 82 FixedLengthValidator oneByteValidator = new FixedLengthValidator(1); 83 mValidators.append(Constants.MESSAGE_RECORD_ON, new VariableLengthValidator(1, 8)); 84 mValidators.append(Constants.MESSAGE_RECORD_STATUS, oneByteValidator); 85 86 // TODO: Handle messages for the Timer Programming. 87 88 // Messages for the System Information. 89 mValidators.append(Constants.MESSAGE_CEC_VERSION, oneByteValidator); 90 mValidators.append(Constants.MESSAGE_SET_MENU_LANGUAGE, new FixedLengthValidator(3)); 91 92 // TODO: Handle messages for the Deck Control. 93 94 // TODO: Handle messages for the Tuner Control. 95 96 // Messages for the Vendor Specific Commands. 97 VariableLengthValidator maxLengthValidator = new VariableLengthValidator(0, 14); 98 mValidators.append(Constants.MESSAGE_DEVICE_VENDOR_ID, new FixedLengthValidator(3)); 99 mValidators.append(Constants.MESSAGE_VENDOR_COMMAND, maxLengthValidator); 100 mValidators.append(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, maxLengthValidator); 101 mValidators.append(Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN, maxLengthValidator); 102 103 // Messages for the OSD. 104 mValidators.append(Constants.MESSAGE_SET_OSD_STRING, maxLengthValidator); 105 mValidators.append(Constants.MESSAGE_SET_OSD_NAME, maxLengthValidator); 106 107 // TODO: Handle messages for the Device Menu Control. 108 109 // Messages for the Remote Control Passthrough. 110 // TODO: Parse the first parameter and determine if it can have the next parameter. 111 mValidators.append(Constants.MESSAGE_USER_CONTROL_PRESSED, 112 new VariableLengthValidator(1, 2)); 113 114 // Messages for the Power Status. 115 mValidators.append(Constants.MESSAGE_REPORT_POWER_STATUS, oneByteValidator); 116 117 // Messages for the General Protocol. 118 mValidators.append(Constants.MESSAGE_FEATURE_ABORT, new FixedLengthValidator(2)); 119 120 // Messages for the System Audio Control. 121 mValidators.append(Constants.MESSAGE_REPORT_AUDIO_STATUS, oneByteValidator); 122 mValidators.append(Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, 123 new FixedLengthValidator(3)); 124 mValidators.append(Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, oneByteValidator); 125 mValidators.append(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, oneByteValidator); 126 mValidators.append(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, oneByteValidator); 127 128 // Messages for the Audio Rate Control. 129 mValidators.append(Constants.MESSAGE_SET_AUDIO_RATE, oneByteValidator); 130 131 // All Messages for the ARC have no parameters. 132 133 // Messages for the Capability Discovery and Control. 134 mValidators.append(Constants.MESSAGE_CDC_MESSAGE, maxLengthValidator); 135 } 136 137 boolean isValid(HdmiCecMessage message) { 138 int opcode = message.getOpcode(); 139 ParameterValidator validator = mValidators.get(opcode); 140 if (validator == null) { 141 Slog.i(TAG, "No validator for the message: " + message); 142 return true; 143 } 144 return validator.isValid(message.getParams()); 145 } 146 147 private static class FixedLengthValidator implements ParameterValidator { 148 private final int mLength; 149 150 public FixedLengthValidator(int length) { 151 mLength = length; 152 } 153 154 @Override 155 public boolean isValid(byte[] params) { 156 return params.length == mLength; 157 } 158 } 159 160 private static class VariableLengthValidator implements ParameterValidator { 161 private final int mMinLength; 162 private final int mMaxLength; 163 164 public VariableLengthValidator(int minLength, int maxLength) { 165 mMinLength = minLength; 166 mMaxLength = maxLength; 167 } 168 169 @Override 170 public boolean isValid(byte[] params) { 171 return params.length >= mMinLength && params.length <= mMaxLength; 172 } 173 } 174 175 private boolean isValidPhysicalAddress(byte[] params, int offset) { 176 int path = HdmiUtils.twoBytesToInt(params, offset); 177 int portId = mService.pathToPortId(path); 178 if (portId == Constants.INVALID_PORT_ID) { 179 return false; 180 } 181 // TODO: Add more logic like validating 1.0.1.0. 182 return true; 183 } 184 185 /** 186 * Check if the given type is valid. A valid type is one of the actual 187 * logical device types defined in the standard ({@link #DEVICE_TV}, 188 * {@link #DEVICE_PLAYBACK}, {@link #DEVICE_TUNER}, {@link #DEVICE_RECORDER}, 189 * and {@link #DEVICE_AUDIO_SYSTEM}). 190 * 191 * @param type device type 192 * @return true if the given type is valid 193 */ 194 static boolean isValidType(int type) { 195 return (HdmiCecDeviceInfo.DEVICE_TV <= type 196 && type <= HdmiCecDeviceInfo.DEVICE_VIDEO_PROCESSOR) 197 && type != HdmiCecDeviceInfo.DEVICE_RESERVED; 198 } 199 200 private class PhysicalAddressValidator implements ParameterValidator { 201 @Override 202 public boolean isValid(byte[] params) { 203 if (params.length != 2) { 204 return false; 205 } 206 return isValidPhysicalAddress(params, 0); 207 } 208 } 209 210 private class ReportPhysicalAddressValidator implements ParameterValidator { 211 @Override 212 public boolean isValid(byte[] params) { 213 if (params.length != 3) { 214 return false; 215 } 216 return isValidPhysicalAddress(params, 0) && isValidType(params[2]); 217 } 218 } 219 220 private class RoutingChangeValidator implements ParameterValidator { 221 @Override 222 public boolean isValid(byte[] params) { 223 if (params.length != 4) { 224 return false; 225 } 226 return isValidPhysicalAddress(params, 0) && isValidPhysicalAddress(params, 2); 227 } 228 } 229} 230