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