1 /*
2  * Copyright 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 #include "StreamHandler.h"
18 
19 #include <aidl/android/hardware/automotive/evs/EvsEventType.h>
20 #include <aidl/android/hardware/automotive/evs/EvsResult.h>
21 #include <aidl/android/hardware/common/NativeHandle.h>
22 #include <android-base/chrono_utils.h>
23 #include <android-base/logging.h>
24 #include <android/hardware_buffer.h>
25 #include <android/hardware_buffer_jni.h>
26 #include <vndk/hardware_buffer.h>
27 
28 namespace {
29 
30 using ::aidl::android::hardware::automotive::evs::BufferDesc;
31 using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
32 using ::aidl::android::hardware::automotive::evs::EvsEventType;
33 using ::aidl::android::hardware::automotive::evs::EvsResult;
34 using ::aidl::android::hardware::automotive::evs::IEvsCamera;
35 using ::aidl::android::hardware::common::NativeHandle;
36 using ::aidl::android::hardware::graphics::common::HardwareBuffer;
37 using ::android::base::ScopedLockAssertion;
38 
dupNativeHandle(const NativeHandle & handle,bool doDup)39 NativeHandle dupNativeHandle(const NativeHandle& handle, bool doDup) {
40     NativeHandle dup;
41 
42     dup.fds = std::vector<::ndk::ScopedFileDescriptor>(handle.fds.size());
43     if (!doDup) {
44         for (auto i = 0; i < handle.fds.size(); ++i) {
45             dup.fds.at(i).set(handle.fds[i].get());
46         }
47     } else {
48         for (auto i = 0; i < handle.fds.size(); ++i) {
49             dup.fds[i] = std::move(handle.fds[i].dup());
50         }
51     }
52     dup.ints = handle.ints;
53 
54     return std::move(dup);
55 }
56 
dupHardwareBuffer(const HardwareBuffer & buffer,bool doDup)57 HardwareBuffer dupHardwareBuffer(const HardwareBuffer& buffer, bool doDup) {
58     HardwareBuffer dup = {
59             .description = buffer.description,
60             .handle = dupNativeHandle(buffer.handle, doDup),
61     };
62 
63     return std::move(dup);
64 }
65 
dupBufferDesc(const BufferDesc & src,bool doDup)66 BufferDesc dupBufferDesc(const BufferDesc& src, bool doDup) {
67     BufferDesc dup = {
68             .buffer = dupHardwareBuffer(src.buffer, doDup),
69             .pixelSizeBytes = src.pixelSizeBytes,
70             .bufferId = src.bufferId,
71             .deviceId = src.deviceId,
72             .timestamp = src.timestamp,
73             .metadata = src.metadata,
74     };
75 
76     return std::move(dup);
77 }
78 
79 }  // namespace
80 
81 namespace android::automotive::evs {
82 
StreamHandler(const std::shared_ptr<IEvsCamera> & camObj,EvsServiceCallback * callback,int maxNumFramesInFlight)83 StreamHandler::StreamHandler(const std::shared_ptr<IEvsCamera>& camObj,
84                              EvsServiceCallback* callback, int maxNumFramesInFlight) :
85       mEvsCamera(camObj), mCallback(callback), mMaxNumFramesInFlightPerClient(maxNumFramesInFlight),
86       mNumClients(0) {
87     if (!camObj) {
88         LOG(ERROR) << "IEvsCamera is invalid.";
89     } else {
90         // We rely on the camera having at least two buffers available since we'll hold one and
91         // expect the camera to be able to capture a new image in the background.
92         auto status = camObj->setMaxFramesInFlight(maxNumFramesInFlight);
93         if (!status.isOk()) {
94             LOG(ERROR) << "Failed to adjust the maximum number of frames in flight: "
95                        << status.getServiceSpecificError();
96         }
97     }
98 }
99 
100 /*
101  * Shuts down a stream handler
102  */
~StreamHandler()103 StreamHandler::~StreamHandler() {
104     shutdown();
105 }
106 
107 /*
108  * Stops an active stream and releases the camera device in use
109  */
shutdown()110 void StreamHandler::shutdown() {
111     // Make sure we're not still streaming
112     blockingStopStream();
113 
114     // At this point, the receiver thread is no longer running, so we can safely drop
115     // our remote object references so they can be freed
116     mEvsCamera = nullptr;
117 }
118 
119 /*
120  * Requests EVS to start a video stream
121  */
startStream()122 bool StreamHandler::startStream() {
123     std::lock_guard<std::mutex> lock(mLock);
124     if (!mRunning) {
125         auto status = mEvsCamera->startVideoStream(ref<StreamHandler>());
126         if (!status.isOk()) {
127             LOG(ERROR) << "StreamHandler failed to start a video stream: "
128                        << status.getServiceSpecificError();
129             return false;
130         }
131 
132         // This is the first client of this stream.
133         mNumClients = 1;
134 
135         // Marks ourselves as running
136         mRunning = true;
137     } else {
138         // Increase a number of active clients and the max. number of frames in
139         // flight.
140         int desired = (++mNumClients) * mMaxNumFramesInFlightPerClient;
141         auto status = mEvsCamera->setMaxFramesInFlight(desired);
142         if (!status.isOk()) {
143             LOG(ERROR) << "Failed to adjust the maximum number of frames in flight for "
144                        << mNumClients << " clients. Error: " << status.getServiceSpecificError();
145             // Decrease a number of clients back.
146             mNumClients -= 1;
147             return false;
148         }
149     }
150 
151     return true;
152 }
153 
154 /*
155  * Requests to stop a video stream and waits for a confirmation
156  */
blockingStopStream()157 void StreamHandler::blockingStopStream() {
158     {
159         std::lock_guard lock(mLock);
160         if (!mRunning) {
161             // Nothing to do.
162             return;
163         }
164 
165         if (mNumClients > 1) {
166             // Decrease a number of active clients and return.
167             --mNumClients;
168             return;
169 
170         }
171 
172         // Return all buffers currently held by us.
173         auto it = mReceivedBuffers.begin();
174         while (it != mReceivedBuffers.end()) {
175             // Packages a returned buffer and sends it back to the camera
176             std::vector<BufferDesc> frames(1);
177             frames[0] = std::move(*it);
178             auto status = mEvsCamera->doneWithFrame(frames);
179             if (!status.isOk()) {
180                 LOG(WARNING) << "Failed to return a frame to EVS service; "
181                              << "this may leak the memory: " << status.getServiceSpecificError();
182             }
183 
184             it = mReceivedBuffers.erase(it);
185         }
186     }
187 
188     auto status = mEvsCamera->stopVideoStream();
189     if (!status.isOk()) {
190         LOG(WARNING) << "stopVideoStream() failed but ignored.";
191     }
192 
193     // Now, we are waiting for the ack from EvsManager service.
194     {
195         std::unique_lock<std::mutex> lock(mLock);
196         ScopedLockAssertion lock_assertion(mLock);
197         while (mRunning) {
198             if (!mCondition.wait_for(lock, 1s, [this]() REQUIRES(mLock) { return !mRunning; })) {
199                 LOG(WARNING) << "STREAM_STOPPED event timer expired.  EVS service may die.";
200                 break;
201             }
202         }
203 
204         // Decrease a number of active clients.
205         --mNumClients;
206     }
207 }
208 
isRunning()209 bool StreamHandler::isRunning() {
210     std::lock_guard<std::mutex> lock(mLock);
211     return mRunning;
212 }
213 
doneWithFrame(int bufferId)214 void StreamHandler::doneWithFrame(int bufferId) {
215     BufferDesc bufferToReturn;
216     {
217         std::lock_guard<std::mutex> lock(mLock);
218         auto it = std::find_if(mReceivedBuffers.begin(), mReceivedBuffers.end(),
219                                [bufferId](BufferDesc& b) { return b.bufferId == bufferId; });
220         if (it == mReceivedBuffers.end()) {
221             LOG(DEBUG) << "Ignores a request to return unknown buffer";
222             return;
223         }
224 
225         bufferToReturn = std::move(*it);
226         mReceivedBuffers.erase(it);
227     }
228 
229     // Packages a returned buffer and sends it back to the camera
230     std::vector<BufferDesc> frames(1);
231     frames[0] = std::move(bufferToReturn);
232     if (auto status = mEvsCamera->doneWithFrame(frames); !status.isOk()) {
233         LOG(ERROR) << "Status = " << status.getStatus();
234         LOG(ERROR) << "Failed to return a frame (id = " << bufferId
235                    << " to EVS service; this may leak the memory: "
236                    << status.getServiceSpecificError();
237     }
238 }
239 
doneWithFrame(const BufferDesc & buffer)240 void StreamHandler::doneWithFrame(const BufferDesc& buffer) {
241     return doneWithFrame(buffer.bufferId);
242 }
243 
deliverFrame(const std::vector<BufferDesc> & buffers)244 ::ndk::ScopedAStatus StreamHandler::deliverFrame(const std::vector<BufferDesc>& buffers) {
245     LOG(DEBUG) << "Received frames from the camera, bufferId = " << buffers[0].bufferId;
246 
247     const BufferDesc& bufferToUse = buffers[0];
248     size_t numBuffersInUse;
249     {
250         std::lock_guard<std::mutex> lock(mLock);
251         numBuffersInUse = mReceivedBuffers.size();
252     }
253 
254     if (numBuffersInUse >= mMaxNumFramesInFlightPerClient) {
255         // We're holding more than what allowed; returns this buffer
256         // immediately.
257         doneWithFrame(bufferToUse);
258         return ::ndk::ScopedAStatus::ok();
259     }
260 
261     {
262         std::lock_guard<std::mutex> lock(mLock);
263         // Records a new frameDesc and forwards to clients
264         mReceivedBuffers.push_back(dupBufferDesc(bufferToUse, /* dup= */ true));
265         LOG(DEBUG) << "Got buffer " << bufferToUse.bufferId
266                    << ", total = " << mReceivedBuffers.size();
267 
268         // Notify anybody who cares that things have changed
269         mCondition.notify_all();
270     }
271 
272     // Forwards a new frame
273     if (!mCallback->onNewFrame(bufferToUse)) {
274         doneWithFrame(bufferToUse);
275         return ::ndk::ScopedAStatus::fromServiceSpecificError(
276                 static_cast<int32_t>(EvsResult::INVALID_ARG));
277     }
278 
279     return ::ndk::ScopedAStatus::ok();
280 }
281 
notify(const EvsEventDesc & event)282 ::ndk::ScopedAStatus StreamHandler::notify(const EvsEventDesc& event) {
283     switch (event.aType) {
284         case EvsEventType::STREAM_STOPPED: {
285             {
286                 std::lock_guard<std::mutex> lock(mLock);
287                 // Signal that the last frame has been received and the stream is stopped
288                 mRunning = false;
289             }
290             LOG(DEBUG) << "Received a STREAM_STOPPED event";
291             break;
292         }
293         case EvsEventType::PARAMETER_CHANGED:
294             LOG(DEBUG) << "Camera parameter 0x" << std::hex << event.payload[0] << " is set to 0x"
295                        << std::hex << event.payload[1];
296             break;
297         // Below events are ignored in reference implementation.
298         case EvsEventType::STREAM_STARTED:
299             [[fallthrough]];
300         case EvsEventType::FRAME_DROPPED:
301             [[fallthrough]];
302         case EvsEventType::TIMEOUT:
303             LOG(INFO) << "Event 0x" << std::hex << static_cast<int32_t>(event.aType)
304                       << " from " << (event.deviceId.empty() ? "Unknown" : event.deviceId)
305                       << " is received but ignored";
306             break;
307         default:
308             LOG(ERROR) << "Unknown event id 0x" << std::hex << static_cast<int32_t>(event.aType);
309             break;
310     }
311 
312     mCallback->onNewEvent(event);
313     return ::ndk::ScopedAStatus::ok();
314 }
315 
316 }  // namespace android::automotive::evs
317