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 #define LOG_TAG "Camera3-BufUtils"
18 #define ATRACE_TAG ATRACE_TAG_CAMERA
19 //#define LOG_NDEBUG 0
20 //#define LOG_NNDEBUG 0  // Per-frame verbose logging
21 
22 #include <inttypes.h>
23 
24 #include <utils/Log.h>
25 
26 #include "device3/BufferUtils.h"
27 
28 namespace android {
29 namespace camera3 {
30 
mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status)31 camera3_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status) {
32     using hardware::camera::device::V3_2::BufferStatus;
33 
34     switch (status) {
35         case BufferStatus::OK: return CAMERA3_BUFFER_STATUS_OK;
36         case BufferStatus::ERROR: return CAMERA3_BUFFER_STATUS_ERROR;
37     }
38     return CAMERA3_BUFFER_STATUS_ERROR;
39 }
40 
takeInflightBufferMap(BufferRecords & other)41 void BufferRecords::takeInflightBufferMap(BufferRecords& other) {
42     std::lock_guard<std::mutex> oLock(other.mInflightLock);
43     std::lock_guard<std::mutex> lock(mInflightLock);
44     if (mInflightBufferMap.size() > 0) {
45         ALOGE("%s: inflight map is set in non-empty state!", __FUNCTION__);
46     }
47     mInflightBufferMap = std::move(other.mInflightBufferMap);
48     other.mInflightBufferMap.clear();
49 }
50 
takeRequestedBufferMap(BufferRecords & other)51 void BufferRecords::takeRequestedBufferMap(BufferRecords& other) {
52     std::lock_guard<std::mutex> oLock(other.mRequestedBuffersLock);
53     std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
54     if (mRequestedBufferMap.size() > 0) {
55         ALOGE("%s: requested buffer map is set in non-empty state!", __FUNCTION__);
56     }
57     mRequestedBufferMap = std::move(other.mRequestedBufferMap);
58     other.mRequestedBufferMap.clear();
59 }
60 
takeBufferCaches(BufferRecords & other,const std::vector<int32_t> & streams)61 void BufferRecords::takeBufferCaches(BufferRecords& other, const std::vector<int32_t>& streams) {
62     std::lock_guard<std::mutex> oLock(other.mBufferIdMapLock);
63     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
64     if (mBufferIdMaps.size() > 0) {
65         ALOGE("%s: buffer ID map is set in non-empty state!", __FUNCTION__);
66     }
67     for (auto streamId : streams) {
68         mBufferIdMaps.insert({streamId, std::move(other.mBufferIdMaps.at(streamId))});
69     }
70     other.mBufferIdMaps.clear();
71 }
72 
getBufferId(const buffer_handle_t & buf,int streamId)73 std::pair<bool, uint64_t> BufferRecords::getBufferId(
74         const buffer_handle_t& buf, int streamId) {
75     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
76 
77     BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
78     auto it = bIdMap.find(buf);
79     if (it == bIdMap.end()) {
80         bIdMap[buf] = mNextBufferId++;
81         ALOGV("stream %d now have %zu buffer caches, buf %p",
82                 streamId, bIdMap.size(), buf);
83         return std::make_pair(true, mNextBufferId - 1);
84     } else {
85         return std::make_pair(false, it->second);
86     }
87 }
88 
tryCreateBufferCache(int streamId)89 void BufferRecords::tryCreateBufferCache(int streamId) {
90     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
91     if (mBufferIdMaps.count(streamId) == 0) {
92         mBufferIdMaps.emplace(streamId, BufferIdMap{});
93     }
94 }
95 
removeInactiveBufferCaches(const std::set<int32_t> & activeStreams)96 void BufferRecords::removeInactiveBufferCaches(const std::set<int32_t>& activeStreams) {
97     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
98     for(auto it = mBufferIdMaps.begin(); it != mBufferIdMaps.end();) {
99         int streamId = it->first;
100         bool active = activeStreams.count(streamId) > 0;
101         if (!active) {
102             it = mBufferIdMaps.erase(it);
103         } else {
104             ++it;
105         }
106     }
107 }
108 
removeOneBufferCache(int streamId,const native_handle_t * handle)109 uint64_t BufferRecords::removeOneBufferCache(int streamId, const native_handle_t* handle) {
110     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
111     uint64_t bufferId = BUFFER_ID_NO_BUFFER;
112     auto mapIt = mBufferIdMaps.find(streamId);
113     if (mapIt == mBufferIdMaps.end()) {
114         // streamId might be from a deleted stream here
115         ALOGI("%s: stream %d has been removed",
116                 __FUNCTION__, streamId);
117         return BUFFER_ID_NO_BUFFER;
118     }
119     BufferIdMap& bIdMap = mapIt->second;
120     auto it = bIdMap.find(handle);
121     if (it == bIdMap.end()) {
122         ALOGW("%s: cannot find buffer %p in stream %d",
123                 __FUNCTION__, handle, streamId);
124         return BUFFER_ID_NO_BUFFER;
125     } else {
126         bufferId = it->second;
127         bIdMap.erase(it);
128         ALOGV("%s: stream %d now have %zu buffer caches after removing buf %p",
129                 __FUNCTION__, streamId, bIdMap.size(), handle);
130     }
131     return bufferId;
132 }
133 
clearBufferCaches(int streamId)134 std::vector<uint64_t> BufferRecords::clearBufferCaches(int streamId) {
135     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
136     std::vector<uint64_t> ret;
137     auto mapIt = mBufferIdMaps.find(streamId);
138     if (mapIt == mBufferIdMaps.end()) {
139         ALOGE("%s: streamId %d not found!", __FUNCTION__, streamId);
140         return ret;
141     }
142     BufferIdMap& bIdMap = mapIt->second;
143     ret.reserve(bIdMap.size());
144     for (const auto& it : bIdMap) {
145         ret.push_back(it.second);
146     }
147     bIdMap.clear();
148     return ret;
149 }
150 
isStreamCached(int streamId)151 bool BufferRecords::isStreamCached(int streamId) {
152     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
153     return mBufferIdMaps.find(streamId) != mBufferIdMaps.end();
154 }
155 
verifyBufferIds(int32_t streamId,std::vector<uint64_t> & bufIds)156 bool BufferRecords::verifyBufferIds(
157         int32_t streamId, std::vector<uint64_t>& bufIds) {
158     std::lock_guard<std::mutex> lock(mBufferIdMapLock);
159     camera3::BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
160     if (bIdMap.size() != bufIds.size()) {
161         ALOGE("%s: stream ID %d buffer cache number mismatch: %zu/%zu (service/HAL)",
162                 __FUNCTION__, streamId, bIdMap.size(), bufIds.size());
163         return false;
164     }
165     std::vector<uint64_t> internalBufIds;
166     internalBufIds.reserve(bIdMap.size());
167     for (const auto& pair : bIdMap) {
168         internalBufIds.push_back(pair.second);
169     }
170     std::sort(bufIds.begin(), bufIds.end());
171     std::sort(internalBufIds.begin(), internalBufIds.end());
172     for (size_t i = 0; i < bufIds.size(); i++) {
173         if (bufIds[i] != internalBufIds[i]) {
174             ALOGE("%s: buffer cache mismatch! Service %" PRIu64 ", HAL %" PRIu64,
175                     __FUNCTION__, internalBufIds[i], bufIds[i]);
176             return false;
177         }
178     }
179     return true;
180 }
181 
getInflightBufferKeys(std::vector<std::pair<int32_t,int32_t>> * out)182 void BufferRecords::getInflightBufferKeys(
183         std::vector<std::pair<int32_t, int32_t>>* out) {
184     std::lock_guard<std::mutex> lock(mInflightLock);
185     out->clear();
186     out->reserve(mInflightBufferMap.size());
187     for (auto& pair : mInflightBufferMap) {
188         uint64_t key = pair.first;
189         int32_t streamId = key & 0xFFFFFFFF;
190         int32_t frameNumber = (key >> 32) & 0xFFFFFFFF;
191         out->push_back(std::make_pair(frameNumber, streamId));
192     }
193     return;
194 }
195 
pushInflightBuffer(int32_t frameNumber,int32_t streamId,buffer_handle_t * buffer)196 status_t BufferRecords::pushInflightBuffer(
197         int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer) {
198     std::lock_guard<std::mutex> lock(mInflightLock);
199     uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
200     mInflightBufferMap[key] = buffer;
201     return OK;
202 }
203 
popInflightBuffer(int32_t frameNumber,int32_t streamId,buffer_handle_t ** buffer)204 status_t BufferRecords::popInflightBuffer(
205         int32_t frameNumber, int32_t streamId,
206         /*out*/ buffer_handle_t **buffer) {
207     std::lock_guard<std::mutex> lock(mInflightLock);
208 
209     uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
210     auto it = mInflightBufferMap.find(key);
211     if (it == mInflightBufferMap.end()) return NAME_NOT_FOUND;
212     if (buffer != nullptr) {
213         *buffer = it->second;
214     }
215     mInflightBufferMap.erase(it);
216     return OK;
217 }
218 
popInflightBuffers(const std::vector<std::pair<int32_t,int32_t>> & buffers)219 void BufferRecords::popInflightBuffers(
220         const std::vector<std::pair<int32_t, int32_t>>& buffers) {
221     for (const auto& pair : buffers) {
222         int32_t frameNumber = pair.first;
223         int32_t streamId = pair.second;
224         popInflightBuffer(frameNumber, streamId, nullptr);
225     }
226 }
227 
pushInflightRequestBuffer(uint64_t bufferId,buffer_handle_t * buf,int32_t streamId)228 status_t BufferRecords::pushInflightRequestBuffer(
229         uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) {
230     std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
231     auto pair = mRequestedBufferMap.insert({bufferId, {streamId, buf}});
232     if (!pair.second) {
233         ALOGE("%s: bufId %" PRIu64 " is already inflight!",
234                 __FUNCTION__, bufferId);
235         return BAD_VALUE;
236     }
237     return OK;
238 }
239 
240 // Find and pop a buffer_handle_t based on bufferId
popInflightRequestBuffer(uint64_t bufferId,buffer_handle_t ** buffer,int32_t * streamId)241 status_t BufferRecords::popInflightRequestBuffer(
242         uint64_t bufferId,
243         /*out*/ buffer_handle_t** buffer,
244         /*optional out*/ int32_t* streamId) {
245     if (buffer == nullptr) {
246         ALOGE("%s: buffer (%p) must not be null", __FUNCTION__, buffer);
247         return BAD_VALUE;
248     }
249     std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
250     auto it = mRequestedBufferMap.find(bufferId);
251     if (it == mRequestedBufferMap.end()) {
252         ALOGE("%s: bufId %" PRIu64 " is not inflight!",
253                 __FUNCTION__, bufferId);
254         return BAD_VALUE;
255     }
256     *buffer = it->second.second;
257     if (streamId != nullptr) {
258         *streamId = it->second.first;
259     }
260     mRequestedBufferMap.erase(it);
261     return OK;
262 }
263 
getInflightRequestBufferKeys(std::vector<uint64_t> * out)264 void BufferRecords::getInflightRequestBufferKeys(
265         std::vector<uint64_t>* out) {
266     std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
267     out->clear();
268     out->reserve(mRequestedBufferMap.size());
269     for (auto& pair : mRequestedBufferMap) {
270         out->push_back(pair.first);
271     }
272     return;
273 }
274 
275 
276 } // camera3
277 } // namespace android
278