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