1 /* 2 * Copyright (C) 2021 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.car; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assume.assumeTrue; 22 23 import android.car.Car; 24 import android.car.evs.CarEvsBufferDescriptor; 25 import android.car.evs.CarEvsManager; 26 import android.car.evs.CarEvsManager.CarEvsStreamEvent; 27 import android.car.evs.CarEvsStatus; 28 import android.os.SystemClock; 29 import android.test.suitebuilder.annotation.MediumTest; 30 import android.util.Log; 31 32 import androidx.test.core.app.ApplicationProvider; 33 import androidx.test.runner.AndroidJUnit4; 34 35 import org.junit.After; 36 import org.junit.Before; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.ArrayList; 41 import java.util.concurrent.CountDownLatch; 42 import java.util.concurrent.ExecutorService; 43 import java.util.concurrent.Executors; 44 import java.util.concurrent.Semaphore; 45 import java.util.concurrent.TimeUnit; 46 47 /* 48 * IMPORTANT NOTE: 49 * This test assumes that EVS HAL is running at the time of test. Depending on the test target, the 50 * reference EVS HAL ($ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver) may be needed. 51 * Please add below line to the target's build script to add the reference EVS HAL to the build: 52 * ENABLE_EVS_SAMPLE := true 53 * 54 * The test will likely fail if no EVS HAL is running on the target device. 55 */ 56 @RunWith(AndroidJUnit4.class) 57 @MediumTest 58 public final class CarEvsManagerTest extends MockedCarTestBase { 59 private static final String TAG = CarEvsManagerTest.class.getSimpleName(); 60 61 // We'd expect that underlying stream runs @10fps at least. 62 private static final int NUMBER_OF_FRAMES_TO_WAIT = 10; 63 private static final int FRAME_TIMEOUT_MS = 1000; 64 private static final int SMALL_NAP_MS = 500; 65 private static final int ACTIVITY_REQUEST_TIMEOUT_SEC = 3; 66 private static final int STREAM_REQUEST_TIMEOUT_SEC = 1; 67 private static final int STREAM_EVENT_TIMEOUT_SEC = 2; 68 69 // Will return frame buffers in the order they arrived. 70 private static final int INDEX_TO_FIRST_ELEM = 0; 71 72 private final ArrayList<CarEvsBufferDescriptor> mReceivedBuffers = new ArrayList<>(); 73 private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1); 74 private final Semaphore mFrameReceivedSignal = new Semaphore(0); 75 private final Semaphore mStreamEventOccurred = new Semaphore(0); 76 77 private final Car mCar = Car.createCar(ApplicationProvider.getApplicationContext()); 78 private final CarEvsManager mEvsManager = 79 (CarEvsManager) mCar.getCarManager(Car.CAR_EVS_SERVICE); 80 private final EvsStreamCallbackImpl mStreamCallback = new EvsStreamCallbackImpl(); 81 private final EvsStatusListenerImpl mStatusListener = new EvsStatusListenerImpl(); 82 83 private @CarEvsStreamEvent int mLastStreamEvent; 84 85 @Before setUp()86 public void setUp() { 87 assumeTrue(mCar.isFeatureEnabled(Car.CAR_EVS_SERVICE)); 88 assertThat(mEvsManager).isNotNull(); 89 assumeTrue(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)); 90 assertThat(mStreamCallback).isNotNull(); 91 assertThat(mStatusListener).isNotNull(); 92 93 // Drains all permits 94 mFrameReceivedSignal.drainPermits(); 95 mStreamEventOccurred.drainPermits(); 96 97 // Ensures no stream is active 98 mEvsManager.stopVideoStream(); 99 } 100 101 @After tearDown()102 public void tearDown() throws Exception { 103 if (mEvsManager != null) { 104 mEvsManager.stopVideoStream(); 105 } 106 } 107 108 @Test testSessionTokenGeneration()109 public void testSessionTokenGeneration() throws Exception { 110 assertThat(mEvsManager.generateSessionToken()).isNotNull(); 111 } 112 113 @Test testStartAndStopVideoStream()114 public void testStartAndStopVideoStream() throws Exception { 115 // Registers a status listener and start monitoring the CarEvsService's state changes. 116 mEvsManager.setStatusListener(mCallbackExecutor, mStatusListener); 117 118 // Requests to start a video stream. 119 assertThat( 120 mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, 121 /* token = */ null, mCallbackExecutor, mStreamCallback) 122 ).isEqualTo(CarEvsManager.ERROR_NONE); 123 124 // Waits for a few frame buffers 125 for (int i = 0; i < NUMBER_OF_FRAMES_TO_WAIT; ++i) { 126 assertThat( 127 mFrameReceivedSignal.tryAcquire(FRAME_TIMEOUT_MS, TimeUnit.MILLISECONDS) 128 ).isTrue(); 129 130 // Nothing to do; returns a buffer immediately 131 CarEvsBufferDescriptor toBeReturned = mReceivedBuffers.get(INDEX_TO_FIRST_ELEM); 132 mReceivedBuffers.remove(INDEX_TO_FIRST_ELEM); 133 mEvsManager.returnFrameBuffer(toBeReturned); 134 } 135 136 // Checks a current status 137 CarEvsStatus status = mEvsManager.getCurrentStatus(); 138 assertThat(status).isNotNull(); 139 assertThat(status.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE); 140 assertThat(status.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW); 141 142 // Then, requests to stop a video stream 143 mEvsManager.stopVideoStream(); 144 145 // Checks a current status a few hundreds milliseconds after. CarEvsService will move into 146 // the inactive state when it gets a stream-stopped event from the EVS manager. 147 SystemClock.sleep(SMALL_NAP_MS); 148 assertThat(mStreamCallback.waitForStreamEvent(CarEvsManager.STREAM_EVENT_STREAM_STOPPED)) 149 .isTrue(); 150 151 // Unregister a listener 152 mEvsManager.clearStatusListener(); 153 } 154 155 @Test testIsSupported()156 public void testIsSupported() throws Exception { 157 assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isTrue(); 158 // TODO(b/179029031): Fix below test when the Surround View service is integrated into 159 // CarEvsService. 160 assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)).isFalse(); 161 } 162 163 /** 164 * Class that implements the listener interface and gets called back from 165 * {@link android.car.evs.CarEvsManager.CarEvsStatusListener}. 166 */ 167 private final class EvsStatusListenerImpl implements CarEvsManager.CarEvsStatusListener { 168 @Override onStatusChanged(CarEvsStatus status)169 public void onStatusChanged(CarEvsStatus status) { 170 Log.i(TAG, "Received a notification of status changed to " + status.getState()); 171 } 172 } 173 174 /** 175 * Class that implements the listener interface and gets called back from 176 * {@link android.hardware.automotive.evs.IEvsCameraStream}. 177 */ 178 private final class EvsStreamCallbackImpl implements CarEvsManager.CarEvsStreamCallback { 179 @Override onStreamEvent(@arEvsStreamEvent int event)180 public void onStreamEvent(@CarEvsStreamEvent int event) { 181 mLastStreamEvent = event; 182 mStreamEventOccurred.release(); 183 } 184 185 @Override onNewFrame(CarEvsBufferDescriptor buffer)186 public void onNewFrame(CarEvsBufferDescriptor buffer) { 187 // Enqueues a new frame 188 mReceivedBuffers.add(buffer); 189 190 // Notifies a new frame's arrival 191 mFrameReceivedSignal.release(); 192 } 193 waitForStreamEvent(@arEvsStreamEvent int expected)194 public boolean waitForStreamEvent(@CarEvsStreamEvent int expected) { 195 while (mLastStreamEvent != expected) { 196 try { 197 if (!mStreamEventOccurred.tryAcquire(STREAM_EVENT_TIMEOUT_SEC, 198 TimeUnit.SECONDS)) { 199 Log.e(TAG, "No stream event is received before the timer expired."); 200 return false; 201 } 202 } catch (InterruptedException e) { 203 Log.e(TAG, "Current waiting thread is interrupted. ", e); 204 return false; 205 } 206 } 207 208 return true; 209 } 210 } 211 } 212