1 /*
2  * Copyright (C) 2022 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 "HalCamera.h"
18 
19 #include "Enumerator.h"
20 #include "ScopedTrace.h"
21 #include "VirtualCamera.h"
22 #include "utils/include/Utils.h"
23 
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 
27 namespace aidl::android::automotive::evs::implementation {
28 
29 using ::aidl::android::hardware::automotive::evs::BufferDesc;
30 using ::aidl::android::hardware::automotive::evs::CameraParam;
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::Stream;
35 using ::android::base::StringAppendF;
36 using ::ndk::ScopedAStatus;
37 
38 // TODO(b/213108625):
39 // We need to hook up death monitoring to detect stream death so we can attempt a reconnect
40 
~HalCamera()41 HalCamera::~HalCamera() {
42     // Reports the usage statistics before the destruction
43     // EvsUsageStatsReported atom is defined in
44     // frameworks/proto_logging/stats/atoms.proto
45     mUsageStats->writeStats();
46 }
47 
makeVirtualCamera()48 std::shared_ptr<VirtualCamera> HalCamera::makeVirtualCamera() {
49     // Create the client camera interface object
50     std::vector<std::shared_ptr<HalCamera>> sourceCameras;
51     sourceCameras.reserve(1);
52     sourceCameras.push_back(ref<HalCamera>());
53     std::shared_ptr<VirtualCamera> client =
54             ::ndk::SharedRefBase::make<VirtualCamera>(sourceCameras);
55     if (!client || !ownVirtualCamera(client)) {
56         LOG(ERROR) << "Failed to create client camera object";
57         return nullptr;
58     }
59 
60     return client;
61 }
62 
ownVirtualCamera(const std::shared_ptr<VirtualCamera> & virtualCamera)63 bool HalCamera::ownVirtualCamera(const std::shared_ptr<VirtualCamera>& virtualCamera) {
64     if (!virtualCamera) {
65         LOG(ERROR) << "A virtual camera object is invalid";
66         return false;
67     }
68 
69     // Make sure we have enough buffers available for all our clients
70     if (!changeFramesInFlight(virtualCamera->getAllowedBuffers())) {
71         // Gah!  We couldn't get enough buffers, so we can't support this virtualCamera
72         // Null the pointer, dropping our reference, thus destroying the virtualCamera object
73         return false;
74     }
75 
76     // Add this virtualCamera to our ownership list via weak pointer
77     mClients.push_back(virtualCamera);
78 
79     // Update statistics
80     mUsageStats->updateNumClients(mClients.size());
81 
82     return true;
83 }
84 
disownVirtualCamera(const VirtualCamera * clientToDisown)85 void HalCamera::disownVirtualCamera(const VirtualCamera* clientToDisown) {
86     // Ignore calls with null pointers
87     if (!clientToDisown) {
88         LOG(WARNING) << "Ignoring disownVirtualCamera call with null pointer";
89         return;
90     }
91 
92     // Remove the virtual camera from our client list
93     const auto clientCount = mClients.size();
94     mClients.remove_if([clientToDisown](std::weak_ptr<VirtualCamera>& client) {
95         auto current = client.lock();
96         return current == nullptr || current.get() == clientToDisown;
97     });
98 
99     if (clientCount == mClients.size()) {
100         LOG(WARNING) << "Couldn't find camera in our client list to remove it; "
101                      << "this client may be removed already.";
102     }
103 
104     // Recompute the number of buffers required with the target camera removed from the list
105     if (!changeFramesInFlight(/* delta= */ 0)) {
106         LOG(WARNING) << "Error when trying to reduce the in flight buffer count";
107     }
108 
109     // Update statistics
110     mUsageStats->updateNumClients(mClients.size());
111 }
112 
changeFramesInFlight(int delta)113 bool HalCamera::changeFramesInFlight(int delta) {
114     // Walk all our clients and count their currently required frames
115     unsigned bufferCount = 0;
116     for (auto&& client : mClients) {
117         std::shared_ptr<VirtualCamera> virtCam = client.lock();
118         if (virtCam) {
119             bufferCount += virtCam->getAllowedBuffers();
120         }
121     }
122 
123     // Add the requested delta
124     bufferCount += delta;
125 
126     // Never drop below 1 buffer -- even if all client cameras get closed
127     if (bufferCount < 1) {
128         bufferCount = 1;
129     }
130 
131     // Ask the hardware for the resulting buffer count
132     if (!mHwCamera->setMaxFramesInFlight(bufferCount).isOk()) {
133         return false;
134     }
135 
136     // Update the size of our array of outstanding frame records
137     std::vector<FrameRecord> newRecords;
138     newRecords.reserve(bufferCount);
139 
140     // Copy and compact the old records that are still active
141     {
142         std::lock_guard lock(mFrameMutex);
143         for (const auto& rec : mFrames) {
144             if (rec.refCount > 0) {
145                 newRecords.push_back(std::move(rec));
146             }
147         }
148         if (newRecords.size() > static_cast<unsigned>(bufferCount)) {
149             LOG(WARNING) << "We found more frames in use than requested.";
150         }
151 
152         mFrames.swap(newRecords);
153     }
154     return true;
155 }
156 
changeFramesInFlight(const std::vector<BufferDesc> & buffers,int * delta)157 bool HalCamera::changeFramesInFlight(const std::vector<BufferDesc>& buffers, int* delta) {
158     // Return immediately if a list is empty.
159     if (buffers.empty()) {
160         LOG(DEBUG) << "No external buffers to add.";
161         return true;
162     }
163 
164     // Walk all our clients and count their currently required frames
165     auto bufferCount = 0;
166     for (auto&& client : mClients) {
167         std::shared_ptr<VirtualCamera> virtCam = client.lock();
168         if (virtCam) {
169             bufferCount += virtCam->getAllowedBuffers();
170         }
171     }
172 
173     // Ask the hardware for the resulting buffer count
174     if (!mHwCamera->importExternalBuffers(buffers, delta).isOk()) {
175         LOG(ERROR) << "Failed to add external capture buffers.";
176         return false;
177     }
178 
179     bufferCount += *delta;
180 
181     // Update the size of our array of outstanding frame records
182     std::vector<FrameRecord> newRecords;
183     newRecords.reserve(bufferCount);
184 
185     {
186         std::lock_guard lock(mFrameMutex);
187         // Copy and compact the old records that are still active
188         for (const auto& rec : mFrames) {
189             if (rec.refCount > 0) {
190                 newRecords.push_back(std::move(rec));
191             }
192         }
193 
194         if (newRecords.size() > static_cast<unsigned>(bufferCount)) {
195             LOG(WARNING) << "We found more frames in use than requested.";
196         }
197 
198         mFrames.swap(newRecords);
199     }
200 
201     return true;
202 }
203 
requestNewFrame(std::shared_ptr<VirtualCamera> client,int64_t lastTimestamp)204 void HalCamera::requestNewFrame(std::shared_ptr<VirtualCamera> client, int64_t lastTimestamp) {
205     ScopedTrace trace("Camera " + getId(), __PRETTY_FUNCTION__);
206     FrameRequest req;
207     req.client = client;
208     req.timestamp = lastTimestamp;
209 
210     std::lock_guard<std::mutex> lock(mFrameMutex);
211     mNextRequests.push_back(req);
212 }
213 
clientStreamStarting()214 ScopedAStatus HalCamera::clientStreamStarting() {
215     {
216         std::lock_guard lock(mFrameMutex);
217         if (mStreamState == RUNNING) {
218             // This camera device is already active.
219             return ScopedAStatus::ok();
220         }
221 
222         if (mStreamState == STOPPED) {
223             // Try to start a video stream.
224             ScopedAStatus status = mHwCamera->startVideoStream(ref<HalCamera>());
225             if (status.isOk()) {
226                 mStreamState = RUNNING;
227             }
228             return status;
229         }
230 
231         // We cannot start a video stream.
232         return Utils::buildScopedAStatusFromEvsResult(
233                 mStreamState == STOPPING ? EvsResult::RESOURCE_BUSY
234                                          : EvsResult::UNDERLYING_SERVICE_ERROR);
235     }
236 }
237 
clientStreamEnding(const VirtualCamera * client)238 void HalCamera::clientStreamEnding(const VirtualCamera* client) {
239     {
240         std::lock_guard<std::mutex> lock(mFrameMutex);
241         if (mStreamState != RUNNING) {
242             // We are being stopped or stopped already.
243             return;
244         }
245 
246         mNextRequests.erase(std::remove_if(mNextRequests.begin(), mNextRequests.end(),
247                                            [client](const auto& r) {
248                                                return r.client.lock().get() == client;
249                                            }),
250                             mNextRequests.end());
251     }
252 
253     // Do we still have a running client?
254     bool stillRunning = false;
255     for (auto&& client : mClients) {
256         std::shared_ptr<VirtualCamera> virtCam = client.lock();
257         if (virtCam) {
258             stillRunning |= virtCam->isStreaming();
259         }
260     }
261 
262     // If not, then stop the hardware stream
263     if (!stillRunning) {
264         {
265             std::lock_guard lock(mFrameMutex);
266             mStreamState = STOPPING;
267         }
268         auto status = mHwCamera->stopVideoStream();
269         if (!status.isOk()) {
270             LOG(WARNING) << "Failed to stop a video stream, error = "
271                          << status.getServiceSpecificError();
272         }
273     }
274 }
275 
doneWithFrame(BufferDesc buffer)276 ScopedAStatus HalCamera::doneWithFrame(BufferDesc buffer) {
277     ScopedTrace trace("Camera " + getId(), __PRETTY_FUNCTION__, buffer.bufferId);
278     std::unique_lock lock(mFrameMutex);
279     ::android::base::ScopedLockAssertion lock_assertion(mFrameMutex);
280     mFrameOpDone.wait(lock, [this]() REQUIRES(mFrameMutex) { return mFrameOpInProgress != true; });
281 
282     // Find this frame in our list of outstanding frames
283     auto it = std::find_if(mFrames.begin(), mFrames.end(),
284                            [id = buffer.bufferId](const FrameRecord& rec) {
285                                return rec.frameId == id;
286                            });
287     if (it == mFrames.end()) {
288         LOG(WARNING) << "We got a frame back with an ID we don't recognize!";
289         return ScopedAStatus::ok();
290     }
291 
292     if (it->refCount < 1) {
293         LOG(WARNING) << "Buffer " << buffer.bufferId
294                      << " is returned with a zero reference counter.";
295         return ScopedAStatus::ok();
296     }
297 
298     // Are there still clients using this buffer?
299     it->refCount = it->refCount - 1;
300     if (it->refCount > 0) {
301         LOG(DEBUG) << "Buffer " << buffer.bufferId << " is still being used by " << it->refCount
302                    << " other client(s).";
303         return ScopedAStatus::ok();
304     }
305 
306     // Since all our clients are done with this buffer, return it to the device layer
307     std::vector<BufferDesc> buffersToReturn(1);
308     buffersToReturn[0] = std::move(buffer);
309     auto status = mHwCamera->doneWithFrame(buffersToReturn);
310     if (!status.isOk()) {
311         LOG(WARNING) << "Failed to return a buffer";
312     }
313 
314     // Counts a returned buffer
315     mUsageStats->framesReturned(buffersToReturn);
316 
317     return status;
318 }
319 
320 // Methods from ::aidl::android::hardware::automotive::evs::IEvsCameraStream follow.
deliverFrame(const std::vector<BufferDesc> & buffers)321 ScopedAStatus HalCamera::deliverFrame(const std::vector<BufferDesc>& buffers) {
322     LOG(VERBOSE) << "Received a frame";
323 
324     ScopedTrace trace("Camera " + getId(), __PRETTY_FUNCTION__,
325                       buffers.empty() ? std::numeric_limits<int>::min() : buffers[0].bufferId);
326 
327     // Reports the number of received buffers
328     mUsageStats->framesReceived(buffers);
329 
330     // Frames are being forwarded to HIDL v1.1 and AIDL clients only who requested new frame.
331     const auto timestamp = buffers[0].timestamp;
332     // TODO(b/145750636): For now, we are using a approximately half of 1 seconds / 30 frames = 33ms
333     //           but this must be derived from current framerate.
334     constexpr int64_t kThreshold = 16'000;  // ms
335     unsigned frameDeliveries = 0;
336     std::deque<FrameRequest> currentRequests;
337     std::deque<FrameRequest> puntedRequests;
338     {
339         std::lock_guard<std::mutex> lock(mFrameMutex);
340         currentRequests.insert(currentRequests.end(),
341                                std::make_move_iterator(mNextRequests.begin()),
342                                std::make_move_iterator(mNextRequests.end()));
343         mNextRequests.clear();
344         mFrameOpInProgress = true;
345     }
346 
347     while (!currentRequests.empty()) {
348         auto req = currentRequests.front();
349         currentRequests.pop_front();
350         std::shared_ptr<VirtualCamera> vCam = req.client.lock();
351         if (!vCam) {
352             // Ignore a client already dead.
353             continue;
354         }
355 
356         if (timestamp - req.timestamp < kThreshold) {
357             // Skip current frame because it arrives too soon.
358             LOG(DEBUG) << "Skips a frame from " << getId();
359             mUsageStats->framesSkippedToSync();
360             puntedRequests.push_back(req);
361             continue;
362         }
363 
364         if (!vCam->deliverFrame(buffers[0])) {
365             LOG(WARNING) << getId() << " failed to forward the buffer to " << vCam.get();
366         } else {
367             LOG(DEBUG) << getId() << " forwarded the buffer #" << buffers[0].bufferId << " to "
368                        << vCam.get() << " from " << this;
369             ++frameDeliveries;
370         }
371     }
372 
373     if (frameDeliveries < 1) {
374         // If none of our clients could accept the frame, then return it
375         // right away.
376         LOG(INFO) << "Trivially rejecting frame (" << buffers[0].bufferId << ") from " << getId()
377                   << " with no acceptance";
378         if (!mHwCamera->doneWithFrame(buffers).isOk()) {
379             LOG(WARNING) << "Failed to return buffers";
380         }
381 
382         // Reports a returned buffer
383         mUsageStats->framesReturned(buffers);
384 
385         // Adding skipped capture requests back to the queue.
386         std::lock_guard<std::mutex> lock(mFrameMutex);
387         mNextRequests.insert(mNextRequests.end(), std::make_move_iterator(puntedRequests.begin()),
388                              std::make_move_iterator(puntedRequests.end()));
389         mFrameOpInProgress = false;
390         mFrameOpDone.notify_all();
391     } else {
392         std::lock_guard lock(mFrameMutex);
393 
394         // Add an entry for this frame in our tracking list.
395         unsigned i;
396         for (i = 0; i < mFrames.size(); ++i) {
397             if (mFrames[i].refCount == 0) {
398                 break;
399             }
400         }
401 
402         if (i == mFrames.size()) {
403             mFrames.emplace_back(buffers[0].bufferId, frameDeliveries);
404         } else {
405             mFrames[i].frameId = buffers[0].bufferId;
406             mFrames[i].refCount = frameDeliveries;
407         }
408 
409         // Adding skipped capture requests back to the queue.
410         mNextRequests.insert(mNextRequests.end(), std::make_move_iterator(puntedRequests.begin()),
411                              std::make_move_iterator(puntedRequests.end()));
412         mFrameOpInProgress = false;
413         mFrameOpDone.notify_all();
414     }
415 
416     return ScopedAStatus::ok();
417 }
418 
notify(const EvsEventDesc & event)419 ScopedAStatus HalCamera::notify(const EvsEventDesc& event) {
420     LOG(DEBUG) << "Received an event id: " << static_cast<int32_t>(event.aType);
421     ScopedTrace trace("Camera " + getId(), __PRETTY_FUNCTION__, static_cast<int>(event.aType));
422     if (event.aType == EvsEventType::STREAM_STOPPED) {
423         // This event happens only when there is no more active client.
424         std::lock_guard lock(mFrameMutex);
425         if (mStreamState != STOPPING) {
426             LOG(WARNING) << "Stream stopped unexpectedly";
427         }
428 
429         mStreamState = STOPPED;
430     }
431 
432     // Forward all other events to the clients
433     for (auto&& client : mClients) {
434         std::shared_ptr<VirtualCamera> virtCam = client.lock();
435         if (virtCam) {
436             if (!virtCam->notify(event)) {
437                 LOG(WARNING) << "Failed to forward an event";
438             }
439         }
440     }
441 
442     return ScopedAStatus::ok();
443 }
444 
setPrimaryClient(const std::shared_ptr<VirtualCamera> & virtualCamera)445 ScopedAStatus HalCamera::setPrimaryClient(const std::shared_ptr<VirtualCamera>& virtualCamera) {
446     if (mPrimaryClient.lock() == nullptr) {
447         LOG(DEBUG) << __FUNCTION__ << ": " << virtualCamera.get() << " becomes a primary client.";
448         mPrimaryClient = virtualCamera;
449         return ScopedAStatus::ok();
450     } else {
451         LOG(INFO) << "This camera already has a primary client.";
452         return Utils::buildScopedAStatusFromEvsResult(EvsResult::PERMISSION_DENIED);
453     }
454 }
455 
forcePrimaryClient(const std::shared_ptr<VirtualCamera> & virtualCamera)456 ScopedAStatus HalCamera::forcePrimaryClient(const std::shared_ptr<VirtualCamera>& virtualCamera) {
457     std::shared_ptr<VirtualCamera> prevPrimary = mPrimaryClient.lock();
458     if (prevPrimary == virtualCamera) {
459         LOG(DEBUG) << "Client " << virtualCamera.get() << " is already a primary client";
460         return ScopedAStatus::ok();
461     }
462 
463     mPrimaryClient = virtualCamera;
464     if (prevPrimary) {
465         LOG(INFO) << "High priority client " << virtualCamera.get()
466                   << " steals a primary role from " << prevPrimary.get();
467 
468         /* Notify a previous primary client the loss of a primary role */
469         EvsEventDesc event;
470         event.aType = EvsEventType::MASTER_RELEASED;
471         auto cbResult = prevPrimary->notify(event);
472         if (!cbResult) {
473             LOG(WARNING) << "Fail to deliver a primary role lost notification";
474         }
475     }
476 
477     return ScopedAStatus::ok();
478 }
479 
unsetPrimaryClient(const VirtualCamera * virtualCamera)480 ScopedAStatus HalCamera::unsetPrimaryClient(const VirtualCamera* virtualCamera) {
481     if (mPrimaryClient.lock().get() != virtualCamera) {
482         return Utils::buildScopedAStatusFromEvsResult(EvsResult::INVALID_ARG);
483     }
484 
485     LOG(INFO) << "Unset a primary camera client";
486     mPrimaryClient.reset();
487 
488     /* Notify other clients that a primary role becomes available. */
489     EvsEventDesc event;
490     event.aType = EvsEventType::MASTER_RELEASED;
491     if (!notify(event).isOk()) {
492         LOG(WARNING) << "Fail to deliver a parameter change notification";
493     }
494 
495     return ScopedAStatus::ok();
496 }
497 
setParameter(const std::shared_ptr<VirtualCamera> & virtualCamera,CameraParam id,int32_t * value)498 ScopedAStatus HalCamera::setParameter(const std::shared_ptr<VirtualCamera>& virtualCamera,
499                                       CameraParam id, int32_t* value) {
500     if (virtualCamera != mPrimaryClient.lock()) {
501         LOG(WARNING) << "A parameter change request from the non-primary client is declined.";
502 
503         /* Read a current value of a requested camera parameter */
504         getParameter(id, value);
505         return Utils::buildScopedAStatusFromEvsResult(EvsResult::PERMISSION_DENIED);
506     }
507 
508     std::vector<int32_t> effectiveValues;
509     auto result = mHwCamera->setIntParameter(id, *value, &effectiveValues);
510     if (result.isOk()) {
511         /* Notify a parameter change */
512         EvsEventDesc event;
513         event.aType = EvsEventType::PARAMETER_CHANGED;
514         event.payload.push_back(static_cast<int32_t>(id));
515         event.payload.push_back(effectiveValues[0]);
516         if (!notify(event).isOk()) {
517             LOG(WARNING) << "Fail to deliver a parameter change notification";
518         }
519 
520         *value = effectiveValues[0];
521     }
522 
523     return result;
524 }
525 
getParameter(CameraParam id,int32_t * value)526 ScopedAStatus HalCamera::getParameter(CameraParam id, int32_t* value) {
527     std::vector<int32_t> effectiveValues;
528     auto result = mHwCamera->getIntParameter(id, &effectiveValues);
529     if (result.isOk()) {
530         *value = effectiveValues[0];
531     }
532 
533     return result;
534 }
535 
getStats() const536 CameraUsageStatsRecord HalCamera::getStats() const {
537     return mUsageStats->snapshot();
538 }
539 
getStreamConfiguration() const540 Stream HalCamera::getStreamConfiguration() const {
541     return mStreamConfig;
542 }
543 
toString(const char * indent) const544 std::string HalCamera::toString(const char* indent) const {
545     std::string buffer;
546 
547     const auto timeElapsedMs = ::android::uptimeMillis() - mTimeCreatedMs;
548     StringAppendF(&buffer, "%sCreated: @%" PRId64 " (elapsed %" PRId64 " ms)\n", indent,
549                   mTimeCreatedMs, timeElapsedMs);
550 
551     std::string double_indent(indent);
552     double_indent += indent;
553     buffer += CameraUsageStats::toString(getStats(), double_indent.data());
554     for (auto&& client : mClients) {
555         auto handle = client.lock();
556         if (!handle) {
557             continue;
558         }
559 
560         StringAppendF(&buffer, "%sClient %p\n", indent, handle.get());
561         buffer += handle->toString(double_indent.data());
562     }
563 
564     StringAppendF(&buffer, "%sPrimary client: %p\n", indent, mPrimaryClient.lock().get());
565 
566     buffer += HalCamera::toString(mStreamConfig, indent);
567 
568     return buffer;
569 }
570 
toString(Stream configuration,const char * indent)571 std::string HalCamera::toString(Stream configuration, const char* indent) {
572     std::string streamInfo;
573     std::string double_indent(indent);
574     double_indent += indent;
575     StringAppendF(&streamInfo,
576                   "%sActive Stream Configuration\n"
577                   "%sid: %d\n"
578                   "%swidth: %d\n"
579                   "%sheight: %d\n"
580                   "%sformat: 0x%X\n"
581                   "%susage: 0x%" PRIx64 "\n"
582                   "%srotation: 0x%X\n\n",
583                   indent, double_indent.data(), configuration.id, double_indent.data(),
584                   configuration.width, double_indent.data(), configuration.height,
585                   double_indent.data(), static_cast<unsigned int>(configuration.format),
586                   double_indent.data(), static_cast<int64_t>(configuration.usage),
587                   double_indent.data(), static_cast<unsigned int>(configuration.rotation));
588 
589     return streamInfo;
590 }
591 
592 }  // namespace aidl::android::automotive::evs::implementation
593