1 /*
2  * Copyright (C) 2023 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 <algorithm>
18 #include <inttypes.h>
19 
20 #include <aidlcommonsupport/NativeHandle.h>
21 #include <sync/sync.h>
22 #include <ui/GraphicBufferMapper.h>
23 
24 #include "CachedStreamBuffer.h"
25 #include "debug.h"
26 
27 namespace android {
28 namespace hardware {
29 namespace camera {
30 namespace provider {
31 namespace implementation {
32 
33 using base::unique_fd;
34 
35 namespace {
importAidlNativeHandle(const NativeHandle & anh)36 const native_handle_t* importAidlNativeHandle(const NativeHandle& anh) {
37     typedef decltype(native_handle_t::version) T;
38     std::vector<T> data(sizeof(native_handle_t) / sizeof(T) + anh.fds.size() +
39         anh.ints.size());
40 
41     native_handle_t* h = native_handle_init(
42         reinterpret_cast<char*>(&data[0]), anh.fds.size(), anh.ints.size());
43     std::transform(anh.fds.begin(), anh.fds.end(), &h->data[0],
44                    [](const ndk::ScopedFileDescriptor& sfd){ return sfd.get(); });
45     std::copy(anh.ints.begin(), anh.ints.end(), &h->data[anh.fds.size()]);
46 
47     const native_handle_t* importedH = nullptr;
48     if (GraphicBufferMapper::get().importBufferNoValidate(h, &importedH) != NO_ERROR) {
49         return FAILURE(nullptr);
50     }
51 
52     return importedH;
53 }
54 
importAidlNativeHandleFence(const NativeHandle & nh)55 unique_fd importAidlNativeHandleFence(const NativeHandle& nh) {
56     const size_t nfds = nh.fds.size();
57     const size_t nints = nh.ints.size();
58 
59     if (nints == 0) {
60         switch (nfds) {
61         case 0:
62             return unique_fd();
63 
64         case 1: {
65                 const int fd = fcntl(nh.fds.front().get(), F_DUPFD_CLOEXEC, 0);
66                 if (fd < 0) {
67                     return FAILURE_V(unique_fd(), "fcntl failed with %s (%d)",
68                                      strerror(errno), errno);
69                 }
70 
71                 return unique_fd(fd);
72             }
73 
74         default:
75             return FAILURE_V(unique_fd(), "unexpected fence shape, nfds=%zu, must "
76                              "be one", nfds);
77         }
78     } else {
79         return unique_fd();
80     }
81 }
82 
moveFenceToAidlNativeHandle(unique_fd fence)83 NativeHandle moveFenceToAidlNativeHandle(unique_fd fence) {
84     if (!fence.ok()) {
85         return {};
86     }
87 
88     typedef decltype(native_handle_t::version) T;
89     T on_stack[sizeof(native_handle_t) / sizeof(T) + 1];
90 
91     native_handle_t* nh = native_handle_init(
92         reinterpret_cast<char*>(&on_stack[0]), 1, 0);
93     nh->data[0] = fence.release();
94     return makeToAidl(nh);
95 }
96 }  //namespace
97 
CachedStreamBuffer(const StreamBuffer & sb)98 CachedStreamBuffer::CachedStreamBuffer(const StreamBuffer& sb)
99         : mBuffer(importAidlNativeHandle(sb.buffer))
100         , mBufferId(sb.bufferId)
101         , mAcquireFence(importAidlNativeHandleFence(sb.acquireFence))
102         , mStreamId(sb.streamId) {
103     LOG_ALWAYS_FATAL_IF(!mBuffer);
104     LOG_ALWAYS_FATAL_IF(!mBufferId);
105     LOG_ALWAYS_FATAL_IF(mStreamId < 0);
106 }
107 
CachedStreamBuffer(CachedStreamBuffer && rhs)108 CachedStreamBuffer::CachedStreamBuffer(CachedStreamBuffer&& rhs) noexcept
109         : mBuffer(std::exchange(rhs.mBuffer, nullptr))
110         , mBufferId(std::exchange(rhs.mBufferId, 0))
111         , mAcquireFence(std::exchange(rhs.mAcquireFence, {}))
112         , mStreamId(std::exchange(rhs.mStreamId, -1))
113         , mProcessed(std::exchange(rhs.mProcessed, true)) {
114     LOG_ALWAYS_FATAL_IF(!mBuffer);
115     LOG_ALWAYS_FATAL_IF(!mBufferId);
116     LOG_ALWAYS_FATAL_IF(mStreamId < 0);
117 }
118 
~CachedStreamBuffer()119 CachedStreamBuffer::~CachedStreamBuffer() {
120     LOG_ALWAYS_FATAL_IF(!mProcessed);
121     if (mStreamId >= 0) {
122         LOG_ALWAYS_FATAL_IF(!mBuffer);
123         LOG_ALWAYS_FATAL_IF(GraphicBufferMapper::get().freeBuffer(mBuffer) != NO_ERROR);
124     }
125 }
126 
importAcquireFence(const NativeHandle & fence)127 void CachedStreamBuffer::importAcquireFence(const NativeHandle& fence) {
128     LOG_ALWAYS_FATAL_IF(!mProcessed);
129     mAcquireFence = importAidlNativeHandleFence(fence);
130     mProcessed = false;
131 }
132 
waitAcquireFence(const unsigned timeoutMs)133 bool CachedStreamBuffer::waitAcquireFence(const unsigned timeoutMs) {
134     if (mAcquireFence.ok()) {
135         if (sync_wait(mAcquireFence.get(), timeoutMs)) {
136             return FAILURE(false);
137         } else {
138             mAcquireFence.reset();
139             return true;
140         }
141     } else {
142         return true;
143     }
144 }
145 
finish(const bool success)146 StreamBuffer CachedStreamBuffer::finish(const bool success) {
147     using aidl::android::hardware::camera::device::BufferStatus;
148     LOG_ALWAYS_FATAL_IF(mProcessed);
149     LOG_ALWAYS_FATAL_IF(!mBufferId);
150     LOG_ALWAYS_FATAL_IF(mStreamId < 0);
151 
152     StreamBuffer sb;
153     sb.streamId = mStreamId;
154     sb.bufferId = mBufferId;
155     sb.status = success ? BufferStatus::OK : BufferStatus::ERROR;
156     sb.releaseFence = moveFenceToAidlNativeHandle(std::move(mAcquireFence));
157 
158     mProcessed = true;
159     return sb;
160 }
161 
162 }  // namespace implementation
163 }  // namespace provider
164 }  // namespace camera
165 }  // namespace hardware
166 }  // namespace android
167