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