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