• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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