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 android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; 19 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK; 20 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV; 21 22 import static com.android.server.hdmi.Constants.ABORT_REFUSED; 23 import static com.android.server.hdmi.Constants.ABORT_UNRECOGNIZED_OPCODE; 24 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM; 25 import static com.android.server.hdmi.Constants.ADDR_BACKUP_1; 26 import static com.android.server.hdmi.Constants.ADDR_BACKUP_2; 27 import static com.android.server.hdmi.Constants.ADDR_BROADCAST; 28 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; 29 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2; 30 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_3; 31 import static com.android.server.hdmi.Constants.ADDR_SPECIFIC_USE; 32 import static com.android.server.hdmi.Constants.ADDR_TV; 33 import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; 34 import static com.android.server.hdmi.Constants.HANDLED; 35 import static com.android.server.hdmi.Constants.MESSAGE_STANDBY; 36 import static com.android.server.hdmi.Constants.NOT_HANDLED; 37 38 import static com.google.common.truth.Truth.assertThat; 39 40 import static junit.framework.Assert.assertEquals; 41 import static junit.framework.Assert.assertFalse; 42 import static junit.framework.Assert.assertTrue; 43 44 import static org.mockito.ArgumentMatchers.any; 45 import static org.mockito.ArgumentMatchers.anyString; 46 import static org.mockito.Mockito.doAnswer; 47 import static org.mockito.Mockito.doNothing; 48 import static org.mockito.Mockito.doReturn; 49 import static org.mockito.Mockito.spy; 50 51 import android.hardware.hdmi.HdmiControlManager; 52 import android.hardware.tv.cec.V1_0.SendMessageResult; 53 import android.os.Binder; 54 import android.os.Looper; 55 import android.os.test.TestLooper; 56 import android.platform.test.annotations.Presubmit; 57 58 import androidx.test.InstrumentationRegistry; 59 import androidx.test.filters.SmallTest; 60 61 import com.android.server.SystemService; 62 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 63 64 import junit.framework.TestCase; 65 66 import org.junit.Before; 67 import org.junit.Test; 68 import org.junit.runner.RunWith; 69 import org.junit.runners.JUnit4; 70 71 import java.util.ArrayList; 72 import java.util.Collections; 73 import java.util.Optional; 74 75 /** Tests for {@link com.android.server.hdmi.HdmiCecController} class. */ 76 @SmallTest 77 @Presubmit 78 @RunWith(JUnit4.class) 79 public class HdmiCecControllerTest { 80 81 private FakeNativeWrapper mNativeWrapper; 82 83 private HdmiControlService mHdmiControlServiceSpy; 84 85 private HdmiCecController mHdmiCecController; 86 private int mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_1_4_B; 87 private int mLogicalAddress = 16; 88 private int mPlaybackLogicalAddress; 89 private AllocateAddressCallback mCallback = 90 new AllocateAddressCallback() { 91 @Override 92 public void onAllocated(int deviceType, int logicalAddress) { 93 mLogicalAddress = logicalAddress; 94 } 95 }; 96 private Looper mMyLooper; 97 private TestLooper mTestLooper = new TestLooper(); 98 99 @Before SetUp()100 public void SetUp() { 101 mMyLooper = mTestLooper.getLooper(); 102 103 FakeAudioFramework audioFramework = new FakeAudioFramework(); 104 105 mHdmiControlServiceSpy = spy(new HdmiControlService( 106 InstrumentationRegistry.getTargetContext(), Collections.emptyList(), 107 audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager())); 108 doReturn(mMyLooper).when(mHdmiControlServiceSpy).getIoLooper(); 109 doReturn(mMyLooper).when(mHdmiControlServiceSpy).getServiceLooper(); 110 doAnswer(__ -> mCecVersion).when(mHdmiControlServiceSpy).getCecVersion(); 111 doNothing().when(mHdmiControlServiceSpy) 112 .writeStringSystemProperty(anyString(), anyString()); 113 mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper()); 114 115 mNativeWrapper = new FakeNativeWrapper(); 116 mHdmiCecController = HdmiCecController.createWithNativeWrapper( 117 mHdmiControlServiceSpy, mNativeWrapper, mHdmiControlServiceSpy.getAtomWriter()); 118 } 119 120 /** Additional setup for tests for onMessage 121 * Adds a local playback device and allocates addresses 122 */ setUpForOnMessageTest()123 public void setUpForOnMessageTest() { 124 mHdmiControlServiceSpy.setCecController(mHdmiCecController); 125 126 HdmiCecLocalDevicePlayback playbackDevice = 127 new HdmiCecLocalDevicePlayback(mHdmiControlServiceSpy); 128 playbackDevice.init(); 129 ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 130 localDevices.add(playbackDevice); 131 132 mHdmiControlServiceSpy.initService(); 133 mHdmiControlServiceSpy.allocateLogicalAddress(localDevices, 134 HdmiControlService.INITIATED_BY_ENABLE_CEC); 135 mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); 136 mTestLooper.dispatchAll(); 137 138 mPlaybackLogicalAddress = playbackDevice.getDeviceInfo().getLogicalAddress(); 139 mTestLooper.dispatchAll(); 140 } 141 142 /** Tests for {@link HdmiCecController#allocateLogicalAddress} */ 143 @Test testAllocateLogicalAddress_TvDevicePreferredNotOccupied()144 public void testAllocateLogicalAddress_TvDevicePreferredNotOccupied() { 145 mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_TV, mCallback); 146 mTestLooper.dispatchAll(); 147 assertEquals(ADDR_TV, mLogicalAddress); 148 } 149 150 @Test testAllocateLogicalAddress_TvDeviceNonPreferredNotOccupied()151 public void testAllocateLogicalAddress_TvDeviceNonPreferredNotOccupied() { 152 mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback); 153 mTestLooper.dispatchAll(); 154 assertEquals(ADDR_TV, mLogicalAddress); 155 } 156 157 @Test testAllocateLogicalAddress_TvDeviceNonPreferredFirstOccupied()158 public void testAllocateLogicalAddress_TvDeviceNonPreferredFirstOccupied() { 159 mNativeWrapper.setPollAddressResponse(ADDR_TV, SendMessageResult.SUCCESS); 160 mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback); 161 mTestLooper.dispatchAll(); 162 assertEquals(ADDR_SPECIFIC_USE, mLogicalAddress); 163 } 164 165 @Test testAllocateLogicalAddress_TvDeviceNonPreferredAllOccupied()166 public void testAllocateLogicalAddress_TvDeviceNonPreferredAllOccupied() { 167 mNativeWrapper.setPollAddressResponse(ADDR_TV, SendMessageResult.SUCCESS); 168 mNativeWrapper.setPollAddressResponse(ADDR_SPECIFIC_USE, SendMessageResult.SUCCESS); 169 mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback); 170 mTestLooper.dispatchAll(); 171 assertEquals(ADDR_UNREGISTERED, mLogicalAddress); 172 } 173 174 @Test testAllocateLogicalAddress_AudioSystemNonPreferredNotOccupied()175 public void testAllocateLogicalAddress_AudioSystemNonPreferredNotOccupied() { 176 mHdmiCecController.allocateLogicalAddress( 177 DEVICE_AUDIO_SYSTEM, ADDR_UNREGISTERED, mCallback); 178 mTestLooper.dispatchAll(); 179 assertEquals(ADDR_AUDIO_SYSTEM, mLogicalAddress); 180 } 181 182 @Test testAllocateLogicalAddress_AudioSystemNonPreferredAllOccupied()183 public void testAllocateLogicalAddress_AudioSystemNonPreferredAllOccupied() { 184 mNativeWrapper.setPollAddressResponse(ADDR_AUDIO_SYSTEM, SendMessageResult.SUCCESS); 185 mHdmiCecController.allocateLogicalAddress( 186 DEVICE_AUDIO_SYSTEM, ADDR_UNREGISTERED, mCallback); 187 mTestLooper.dispatchAll(); 188 assertEquals(ADDR_UNREGISTERED, mLogicalAddress); 189 } 190 191 @Test testAllocateLogicalAddress_PlaybackPreferredNotOccupied()192 public void testAllocateLogicalAddress_PlaybackPreferredNotOccupied() { 193 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback); 194 mTestLooper.dispatchAll(); 195 assertEquals(ADDR_PLAYBACK_1, mLogicalAddress); 196 } 197 198 @Test testAllocateLogicalAddress_PlaybackPreferredOccupied()199 public void testAllocateLogicalAddress_PlaybackPreferredOccupied() { 200 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); 201 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback); 202 mTestLooper.dispatchAll(); 203 assertEquals(ADDR_PLAYBACK_2, mLogicalAddress); 204 } 205 206 @Test testAllocateLogicalAddress_PlaybackNoPreferredNotOccupied()207 public void testAllocateLogicalAddress_PlaybackNoPreferredNotOccupied() { 208 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback); 209 mTestLooper.dispatchAll(); 210 assertEquals(ADDR_PLAYBACK_1, mLogicalAddress); 211 } 212 213 @Test testAllocateLogicalAddress_PlaybackNoPreferredFirstOccupied()214 public void testAllocateLogicalAddress_PlaybackNoPreferredFirstOccupied() { 215 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); 216 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback); 217 mTestLooper.dispatchAll(); 218 assertEquals(ADDR_PLAYBACK_2, mLogicalAddress); 219 } 220 221 @Test testAllocateLogicalAddress_PlaybackNonPreferredFirstTwoOccupied()222 public void testAllocateLogicalAddress_PlaybackNonPreferredFirstTwoOccupied() { 223 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); 224 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS); 225 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback); 226 mTestLooper.dispatchAll(); 227 assertEquals(ADDR_PLAYBACK_3, mLogicalAddress); 228 } 229 230 @Test testAllocateLogicalAddress_PlaybackNonPreferredAllOccupied()231 public void testAllocateLogicalAddress_PlaybackNonPreferredAllOccupied() { 232 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); 233 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS); 234 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_3, SendMessageResult.SUCCESS); 235 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback); 236 mTestLooper.dispatchAll(); 237 assertEquals(ADDR_UNREGISTERED, mLogicalAddress); 238 } 239 240 @Test testAllocateLogicalAddress_PlaybackNonPreferred_2_0_BackupOne()241 public void testAllocateLogicalAddress_PlaybackNonPreferred_2_0_BackupOne() { 242 mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; 243 244 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); 245 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS); 246 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_3, SendMessageResult.SUCCESS); 247 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback); 248 mTestLooper.dispatchAll(); 249 assertEquals(ADDR_BACKUP_1, mLogicalAddress); 250 } 251 252 @Test testAllocateLogicalAddress_PlaybackNonPreferred_2_0_BackupTwo()253 public void testAllocateLogicalAddress_PlaybackNonPreferred_2_0_BackupTwo() { 254 mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; 255 256 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); 257 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS); 258 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_3, SendMessageResult.SUCCESS); 259 mNativeWrapper.setPollAddressResponse(ADDR_BACKUP_1, SendMessageResult.SUCCESS); 260 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback); 261 mTestLooper.dispatchAll(); 262 assertEquals(ADDR_BACKUP_2, mLogicalAddress); 263 } 264 265 @Test testAllocateLogicalAddress_PlaybackPreferredOccupiedDedicatedBelowAvailable()266 public void testAllocateLogicalAddress_PlaybackPreferredOccupiedDedicatedBelowAvailable() { 267 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS); 268 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_3, SendMessageResult.SUCCESS); 269 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_2, mCallback); 270 mTestLooper.dispatchAll(); 271 assertEquals(ADDR_PLAYBACK_1, mLogicalAddress); 272 } 273 274 @Test testAllocateLogicalAddress_PlaybackPreferredOccupiedDedicatedAboveAvailable()275 public void testAllocateLogicalAddress_PlaybackPreferredOccupiedDedicatedAboveAvailable() { 276 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); 277 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS); 278 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_2, mCallback); 279 mTestLooper.dispatchAll(); 280 assertEquals(ADDR_PLAYBACK_3, mLogicalAddress); 281 } 282 283 @Test testAllocateLogicalAddress_PlaybackNonPreferred_2_0_AllOccupied()284 public void testAllocateLogicalAddress_PlaybackNonPreferred_2_0_AllOccupied() { 285 mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; 286 287 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); 288 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS); 289 mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_3, SendMessageResult.SUCCESS); 290 mNativeWrapper.setPollAddressResponse(ADDR_BACKUP_1, SendMessageResult.SUCCESS); 291 mNativeWrapper.setPollAddressResponse(ADDR_BACKUP_2, SendMessageResult.SUCCESS); 292 mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback); 293 mTestLooper.dispatchAll(); 294 assertEquals(ADDR_UNREGISTERED, mLogicalAddress); 295 } 296 297 @Test testIsLanguage()298 public void testIsLanguage() { 299 assertTrue(HdmiCecController.isLanguage("en")); 300 assertTrue(HdmiCecController.isLanguage("eng")); 301 assertTrue(HdmiCecController.isLanguage("ger")); 302 assertTrue(HdmiCecController.isLanguage("zh")); 303 assertTrue(HdmiCecController.isLanguage("zhi")); 304 assertTrue(HdmiCecController.isLanguage("zho")); 305 306 assertFalse(HdmiCecController.isLanguage(null)); 307 assertFalse(HdmiCecController.isLanguage("")); 308 assertFalse(HdmiCecController.isLanguage("e")); 309 assertFalse(HdmiCecController.isLanguage("一")); // language code must be ASCII 310 } 311 312 @Test runOnServiceThread_preservesAndRestoresWorkSourceUid()313 public void runOnServiceThread_preservesAndRestoresWorkSourceUid() { 314 Binder.setCallingWorkSourceUid(1234); 315 WorkSourceUidReadingRunnable uidReadingRunnable = new WorkSourceUidReadingRunnable(); 316 mHdmiCecController.runOnServiceThread(uidReadingRunnable); 317 318 Binder.setCallingWorkSourceUid(5678); 319 mTestLooper.dispatchAll(); 320 321 TestCase.assertEquals(Optional.of(1234), uidReadingRunnable.getWorkSourceUid()); 322 TestCase.assertEquals(5678, Binder.getCallingWorkSourceUid()); 323 } 324 325 @Test runOnIoThread_preservesAndRestoresWorkSourceUid()326 public void runOnIoThread_preservesAndRestoresWorkSourceUid() { 327 int callerUid = 1234; 328 int runnerUid = 5678; 329 330 Binder.setCallingWorkSourceUid(callerUid); 331 WorkSourceUidReadingRunnable uidReadingRunnable = new WorkSourceUidReadingRunnable(); 332 mHdmiCecController.runOnIoThread(uidReadingRunnable); 333 334 Binder.setCallingWorkSourceUid(runnerUid); 335 mTestLooper.dispatchAll(); 336 337 TestCase.assertEquals(Optional.of(callerUid), uidReadingRunnable.getWorkSourceUid()); 338 TestCase.assertEquals(runnerUid, Binder.getCallingWorkSourceUid()); 339 } 340 341 @Test onMessage_broadcastMessage_doesNotSendFeatureAbort()342 public void onMessage_broadcastMessage_doesNotSendFeatureAbort() { 343 setUpForOnMessageTest(); 344 345 doReturn(ABORT_UNRECOGNIZED_OPCODE).when(mHdmiControlServiceSpy).handleCecCommand(any()); 346 347 HdmiCecMessage receivedMessage = HdmiCecMessageBuilder.buildStandby( 348 ADDR_TV, ADDR_BROADCAST); 349 350 mNativeWrapper.onCecMessage(receivedMessage); 351 352 mTestLooper.dispatchAll(); 353 354 assertFalse("No <Feature Abort> messages should be sent", 355 mNativeWrapper.getResultMessages().stream().anyMatch( 356 message -> message.getOpcode() == Constants.MESSAGE_FEATURE_ABORT)); 357 } 358 359 @Test onMessage_notTheDestination_doesNotSendFeatureAbort()360 public void onMessage_notTheDestination_doesNotSendFeatureAbort() { 361 setUpForOnMessageTest(); 362 363 doReturn(ABORT_UNRECOGNIZED_OPCODE).when(mHdmiControlServiceSpy).handleCecCommand(any()); 364 365 HdmiCecMessage receivedMessage = HdmiCecMessageBuilder.buildStandby( 366 ADDR_TV, ADDR_AUDIO_SYSTEM); 367 mNativeWrapper.onCecMessage(receivedMessage); 368 369 mTestLooper.dispatchAll(); 370 371 assertFalse("No <Feature Abort> messages should be sent", 372 mNativeWrapper.getResultMessages().stream().anyMatch( 373 message -> message.getOpcode() == Constants.MESSAGE_FEATURE_ABORT)); 374 } 375 376 @Test onMessage_handledMessage_doesNotSendFeatureAbort()377 public void onMessage_handledMessage_doesNotSendFeatureAbort() { 378 setUpForOnMessageTest(); 379 380 doReturn(HANDLED).when(mHdmiControlServiceSpy).handleCecCommand(any()); 381 382 HdmiCecMessage receivedMessage = HdmiCecMessageBuilder.buildStandby( 383 ADDR_TV, mPlaybackLogicalAddress); 384 mNativeWrapper.onCecMessage(receivedMessage); 385 386 mTestLooper.dispatchAll(); 387 388 assertFalse("No <Feature Abort> messages should be sent", 389 mNativeWrapper.getResultMessages().stream().anyMatch( 390 message -> message.getOpcode() == Constants.MESSAGE_FEATURE_ABORT)); 391 } 392 393 @Test onMessage_unhandledMessage_sendsFeatureAbortUnrecognizedOpcode()394 public void onMessage_unhandledMessage_sendsFeatureAbortUnrecognizedOpcode() { 395 setUpForOnMessageTest(); 396 397 doReturn(NOT_HANDLED).when(mHdmiControlServiceSpy).handleCecCommand(any()); 398 399 HdmiCecMessage receivedMessage = HdmiCecMessageBuilder.buildStandby( 400 ADDR_TV, mPlaybackLogicalAddress); 401 mNativeWrapper.onCecMessage(receivedMessage); 402 403 mTestLooper.dispatchAll(); 404 405 HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( 406 mPlaybackLogicalAddress, DEVICE_TV, MESSAGE_STANDBY, ABORT_UNRECOGNIZED_OPCODE); 407 assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort); 408 } 409 410 @Test onMessage_sendsFeatureAbortWithRequestedOperand()411 public void onMessage_sendsFeatureAbortWithRequestedOperand() { 412 setUpForOnMessageTest(); 413 414 doReturn(ABORT_REFUSED).when(mHdmiControlServiceSpy).handleCecCommand(any()); 415 416 HdmiCecMessage receivedMessage = HdmiCecMessageBuilder.buildStandby( 417 ADDR_TV, mPlaybackLogicalAddress); 418 mNativeWrapper.onCecMessage(receivedMessage); 419 420 mTestLooper.dispatchAll(); 421 422 HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( 423 mPlaybackLogicalAddress, DEVICE_TV, MESSAGE_STANDBY, ABORT_REFUSED); 424 assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort); 425 } 426 } 427