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