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