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