1 /* 2 * Copyright (C) 2018 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 package com.android.server.hdmi; 17 18 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; 19 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; 20 import static com.android.server.hdmi.Constants.ADDR_TV; 21 import static com.android.server.hdmi.Constants.PATH_RELATIONSHIP_ANCESTOR; 22 23 import static org.mockito.ArgumentMatchers.any; 24 import static org.mockito.ArgumentMatchers.anyInt; 25 import static org.mockito.ArgumentMatchers.anyString; 26 import static org.mockito.ArgumentMatchers.eq; 27 import static org.mockito.Mockito.atLeastOnce; 28 import static org.mockito.Mockito.doNothing; 29 import static org.mockito.Mockito.doReturn; 30 import static org.mockito.Mockito.spy; 31 import static org.mockito.Mockito.times; 32 import static org.mockito.Mockito.verify; 33 34 import android.content.Context; 35 import android.content.ContextWrapper; 36 import android.hardware.hdmi.HdmiControlManager; 37 import android.hardware.hdmi.HdmiDeviceInfo; 38 import android.hardware.hdmi.HdmiPortInfo; 39 import android.hardware.tv.cec.V1_0.SendMessageResult; 40 import android.os.Binder; 41 import android.os.Looper; 42 import android.os.RemoteException; 43 import android.os.test.TestLooper; 44 import android.platform.test.annotations.Presubmit; 45 import android.stats.hdmi.HdmiStatsEnums; 46 47 import androidx.test.InstrumentationRegistry; 48 import androidx.test.filters.SmallTest; 49 50 import com.android.server.SystemService; 51 52 import org.junit.Before; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.junit.runners.JUnit4; 56 import org.mockito.Mockito; 57 58 import java.util.Collections; 59 60 /** 61 * Tests for the {@link HdmiCecAtomWriter} class and its usage by the HDMI-CEC framework. 62 */ 63 @SmallTest 64 @Presubmit 65 @RunWith(JUnit4.class) 66 public class HdmiCecAtomLoggingTest { 67 private HdmiCecAtomWriter mHdmiCecAtomWriterSpy; 68 private HdmiControlService mHdmiControlServiceSpy; 69 private HdmiCecController mHdmiCecController; 70 private HdmiMhlControllerStub mHdmiMhlControllerStub; 71 private FakeNativeWrapper mNativeWrapper; 72 private FakePowerManagerWrapper mPowerManager; 73 private HdmiCecNetwork mHdmiCecNetwork; 74 private Looper mLooper; 75 private Context mContextSpy; 76 private TestLooper mTestLooper = new TestLooper(); 77 private int mPhysicalAddress = 0x1110; 78 private HdmiPortInfo[] mHdmiPortInfo; 79 80 @Before setUp()81 public void setUp() throws RemoteException { 82 mHdmiCecAtomWriterSpy = spy(new HdmiCecAtomWriter()); 83 84 mLooper = mTestLooper.getLooper(); 85 86 mContextSpy = spy(new ContextWrapper( 87 InstrumentationRegistry.getInstrumentation().getTargetContext())); 88 89 FakeAudioFramework audioFramework = new FakeAudioFramework(); 90 91 mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, 92 Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), 93 audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager())); 94 doNothing().when(mHdmiControlServiceSpy) 95 .writeStringSystemProperty(anyString(), anyString()); 96 doReturn(mHdmiCecAtomWriterSpy).when(mHdmiControlServiceSpy).getAtomWriter(); 97 98 HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); 99 doReturn(hdmiCecConfig).when(mHdmiControlServiceSpy).getHdmiCecConfig(); 100 101 mHdmiControlServiceSpy.setIoLooper(mLooper); 102 mHdmiControlServiceSpy.setCecMessageBuffer( 103 new CecMessageBuffer(mHdmiControlServiceSpy)); 104 105 mNativeWrapper = new FakeNativeWrapper(); 106 mNativeWrapper.setPhysicalAddress(mPhysicalAddress); 107 108 mHdmiCecController = HdmiCecController.createWithNativeWrapper( 109 mHdmiControlServiceSpy, mNativeWrapper, mHdmiCecAtomWriterSpy); 110 mHdmiControlServiceSpy.setCecController(mHdmiCecController); 111 112 mHdmiMhlControllerStub = HdmiMhlControllerStub.create(mHdmiControlServiceSpy); 113 mHdmiControlServiceSpy.setHdmiMhlController( 114 mHdmiMhlControllerStub); 115 116 mHdmiCecNetwork = new HdmiCecNetwork(mHdmiControlServiceSpy, 117 mHdmiCecController, mHdmiMhlControllerStub); 118 mHdmiControlServiceSpy.setHdmiCecNetwork(mHdmiCecNetwork); 119 mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper()); 120 121 HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1]; 122 hdmiPortInfos[0] = 123 new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000) 124 .setCecSupported(true) 125 .setMhlSupported(false) 126 .setArcSupported(false) 127 .build(); 128 mNativeWrapper.setPortInfo(hdmiPortInfos); 129 mNativeWrapper.setPortConnectionStatus(1, true); 130 131 mHdmiControlServiceSpy.initService(); 132 mPowerManager = new FakePowerManagerWrapper(mContextSpy); 133 mHdmiControlServiceSpy.setPowerManager(mPowerManager); 134 mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); 135 136 mTestLooper.dispatchAll(); 137 138 Mockito.reset(mHdmiCecAtomWriterSpy); 139 } 140 141 @Test testActiveSourceChanged_calledOnSetActiveSource()142 public void testActiveSourceChanged_calledOnSetActiveSource() { 143 mHdmiControlServiceSpy.setActiveSource(1, 0x1111, "caller"); 144 verify(mHdmiCecAtomWriterSpy, times(1)) 145 .activeSourceChanged(1, 0x1111, PATH_RELATIONSHIP_ANCESTOR); 146 } 147 148 @Test testMessageReported_calledOnOutgoingMessage()149 public void testMessageReported_calledOnOutgoingMessage() { 150 HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, 151 mPhysicalAddress); 152 153 mHdmiCecController.sendCommand(message); 154 mTestLooper.dispatchAll(); 155 156 verify(mHdmiCecAtomWriterSpy, times(1)).messageReported( 157 eq(message), 158 eq(HdmiStatsEnums.OUTGOING), 159 anyInt(), 160 eq(SendMessageResult.SUCCESS)); 161 } 162 163 @Test testMessageReported_calledOnIncomingMessage()164 public void testMessageReported_calledOnIncomingMessage() { 165 HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000); 166 167 mNativeWrapper.onCecMessage(message); 168 mTestLooper.dispatchAll(); 169 170 verify(mHdmiCecAtomWriterSpy, times(1)).messageReported( 171 eq(message), 172 eq(HdmiStatsEnums.INCOMING), 173 anyInt()); 174 } 175 176 @Test testMessageReported_calledWithUid()177 public void testMessageReported_calledWithUid() { 178 int callerUid = 1234; 179 int runnerUid = 5678; 180 181 mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON); 182 mHdmiControlServiceSpy.onBootPhase(PHASE_BOOT_COMPLETED); 183 184 Binder.setCallingWorkSourceUid(callerUid); 185 186 mHdmiControlServiceSpy.runOnServiceThread( 187 () -> mHdmiControlServiceSpy.setStandbyMode(true)); 188 189 Binder.setCallingWorkSourceUid(runnerUid); 190 191 mTestLooper.dispatchAll(); 192 193 verify(mHdmiCecAtomWriterSpy, atLeastOnce()).messageReported( 194 any(), 195 anyInt(), 196 eq(callerUid), 197 anyInt()); 198 } 199 200 @Test testMessageReported_writesAtom_userControlPressed()201 public void testMessageReported_writesAtom_userControlPressed() { 202 HdmiCecMessage message = HdmiCecMessageBuilder.buildUserControlPressed( 203 Constants.ADDR_TV, 204 Constants.ADDR_PLAYBACK_1, 205 HdmiCecKeycode.CEC_KEYCODE_MUTE 206 ); 207 208 mHdmiCecAtomWriterSpy.messageReported( 209 message, 210 HdmiStatsEnums.INCOMING, 211 1234); 212 213 verify(mHdmiCecAtomWriterSpy, times(1)) 214 .writeHdmiCecMessageReportedAtom( 215 1234, 216 HdmiStatsEnums.INCOMING, 217 Constants.ADDR_TV, 218 Constants.ADDR_PLAYBACK_1, 219 Constants.MESSAGE_USER_CONTROL_PRESSED, 220 HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN, 221 HdmiStatsEnums.VOLUME_MUTE, 222 HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN, 223 HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN); 224 } 225 226 @Test testMessageReported_writesAtom_userControlPressed_noParams()227 public void testMessageReported_writesAtom_userControlPressed_noParams() { 228 HdmiCecMessage message = HdmiCecMessage.build( 229 Constants.ADDR_TV, 230 Constants.ADDR_PLAYBACK_1, 231 Constants.MESSAGE_USER_CONTROL_PRESSED, 232 new byte[0]); 233 234 mHdmiCecAtomWriterSpy.messageReported( 235 message, 236 HdmiStatsEnums.INCOMING, 237 1234); 238 239 verify(mHdmiCecAtomWriterSpy, times(1)) 240 .writeHdmiCecMessageReportedAtom( 241 1234, 242 HdmiStatsEnums.INCOMING, 243 Constants.ADDR_TV, 244 Constants.ADDR_PLAYBACK_1, 245 Constants.MESSAGE_USER_CONTROL_PRESSED, 246 HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN, 247 HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN, 248 HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN, 249 HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN); 250 } 251 252 @Test testMessageReported_writesAtom_featureAbort()253 public void testMessageReported_writesAtom_featureAbort() { 254 HdmiCecMessage message = HdmiCecMessageBuilder.buildFeatureAbortCommand( 255 Constants.ADDR_TV, 256 Constants.ADDR_PLAYBACK_1, 257 Constants.MESSAGE_RECORD_ON, 258 Constants.ABORT_UNRECOGNIZED_OPCODE 259 ); 260 261 mHdmiCecAtomWriterSpy.messageReported( 262 message, 263 HdmiStatsEnums.INCOMING, 264 1234); 265 266 verify(mHdmiCecAtomWriterSpy, times(1)) 267 .writeHdmiCecMessageReportedAtom( 268 1234, 269 HdmiStatsEnums.INCOMING, 270 Constants.ADDR_TV, 271 Constants.ADDR_PLAYBACK_1, 272 Constants.MESSAGE_FEATURE_ABORT, 273 HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN, 274 HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN, 275 Constants.MESSAGE_RECORD_ON, 276 HdmiStatsEnums.UNRECOGNIZED_OPCODE); 277 } 278 279 @Test testMessageReported_writesAtom_featureAbort_noParams()280 public void testMessageReported_writesAtom_featureAbort_noParams() { 281 HdmiCecMessage message = HdmiCecMessage.build( 282 Constants.ADDR_TV, 283 Constants.ADDR_PLAYBACK_1, 284 Constants.MESSAGE_FEATURE_ABORT, 285 new byte[0]); 286 287 mHdmiCecAtomWriterSpy.messageReported( 288 message, 289 HdmiStatsEnums.INCOMING, 290 1234); 291 292 verify(mHdmiCecAtomWriterSpy, times(1)) 293 .writeHdmiCecMessageReportedAtom( 294 1234, 295 HdmiStatsEnums.INCOMING, 296 Constants.ADDR_TV, 297 Constants.ADDR_PLAYBACK_1, 298 Constants.MESSAGE_FEATURE_ABORT, 299 HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN, 300 HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN, 301 HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN, 302 HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN); 303 } 304 } 305