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_NDEBUG 0
18 #define LOG_TAG "GCH_PendingRequestsTracker"
19 #define ATRACE_TAG ATRACE_TAG_CAMERA
20 #include <log/log.h>
21 #include <utils/Trace.h>
22
23 #include "pending_requests_tracker.h"
24
25 namespace android {
26 namespace google_camera_hal {
27
Create(const std::vector<HalStream> & hal_configured_streams,const std::unordered_map<int32_t,int32_t> & grouped_stream_id_map)28 std::unique_ptr<PendingRequestsTracker> PendingRequestsTracker::Create(
29 const std::vector<HalStream>& hal_configured_streams,
30 const std::unordered_map<int32_t, int32_t>& grouped_stream_id_map) {
31 auto tracker =
32 std::unique_ptr<PendingRequestsTracker>(new PendingRequestsTracker());
33 if (tracker == nullptr) {
34 ALOGE("%s: Failed to create PendingRequestsTracker", __FUNCTION__);
35 return nullptr;
36 }
37
38 status_t res =
39 tracker->Initialize(hal_configured_streams, grouped_stream_id_map);
40 if (res != OK) {
41 ALOGE("%s: Initializing stream buffer tracker failed: %s(%d)", __FUNCTION__,
42 strerror(-res), res);
43 return nullptr;
44 }
45
46 return tracker;
47 }
48
Initialize(const std::vector<HalStream> & hal_configured_streams,const std::unordered_map<int32_t,int32_t> & grouped_stream_id_map)49 status_t PendingRequestsTracker::Initialize(
50 const std::vector<HalStream>& hal_configured_streams,
51 const std::unordered_map<int32_t, int32_t>& grouped_stream_id_map) {
52 grouped_stream_id_map_ = grouped_stream_id_map;
53 for (auto& hal_stream : hal_configured_streams) {
54 int hal_stream_id = OverrideStreamIdForGroup(hal_stream.id);
55 // For grouped hal streams, only use one stream to represent the whole group
56 if (hal_stream_id == hal_stream.id) {
57 auto [max_buffer_it, max_buffer_inserted] =
58 stream_max_buffers_.emplace(hal_stream_id, hal_stream.max_buffers);
59 if (!max_buffer_inserted) {
60 ALOGE("%s: There are duplicated stream id %d", __FUNCTION__,
61 hal_stream_id);
62 return BAD_VALUE;
63 }
64
65 stream_pending_buffers_.emplace(hal_stream_id, /*pending_buffers=*/0);
66 stream_acquired_buffers_.emplace(hal_stream_id, /*pending_buffers=*/0);
67 }
68 }
69
70 return OK;
71 }
72
IsStreamConfigured(int32_t stream_id) const73 bool PendingRequestsTracker::IsStreamConfigured(int32_t stream_id) const {
74 return stream_max_buffers_.find(stream_id) != stream_max_buffers_.end();
75 }
76
OverrideStreamIdForGroup(int32_t stream_id) const77 int32_t PendingRequestsTracker::OverrideStreamIdForGroup(int32_t stream_id) const {
78 if (grouped_stream_id_map_.count(stream_id) == 1) {
79 return grouped_stream_id_map_.at(stream_id);
80 } else {
81 return stream_id;
82 }
83 }
84
TrackRequestBuffersLocked(const std::vector<StreamBuffer> & requested_buffers)85 void PendingRequestsTracker::TrackRequestBuffersLocked(
86 const std::vector<StreamBuffer>& requested_buffers) {
87 ATRACE_CALL();
88
89 for (auto& buffer : requested_buffers) {
90 int32_t stream_id = OverrideStreamIdForGroup(buffer.stream_id);
91 if (!IsStreamConfigured(stream_id)) {
92 ALOGW("%s: stream %d was not configured.", __FUNCTION__, stream_id);
93 // Continue to track other buffers.
94 continue;
95 }
96
97 stream_pending_buffers_[stream_id]++;
98 }
99 }
100
TrackReturnedResultBuffers(const std::vector<StreamBuffer> & returned_buffers)101 status_t PendingRequestsTracker::TrackReturnedResultBuffers(
102 const std::vector<StreamBuffer>& returned_buffers) {
103 ATRACE_CALL();
104
105 {
106 std::lock_guard<std::mutex> lock(pending_requests_mutex_);
107 for (auto& buffer : returned_buffers) {
108 int32_t stream_id = OverrideStreamIdForGroup(buffer.stream_id);
109 if (!IsStreamConfigured(stream_id)) {
110 ALOGW("%s: stream %d was not configured.", __FUNCTION__, stream_id);
111 // Continue to track other buffers.
112 continue;
113 }
114
115 if (stream_pending_buffers_[stream_id] == 0) {
116 ALOGE("%s: stream %d should not have any pending quota buffers.",
117 __FUNCTION__, stream_id);
118 // Continue to track other buffers.
119 continue;
120 }
121
122 stream_pending_buffers_[stream_id]--;
123 if (stream_pending_buffers_[stream_id] == 0) {
124 ALOGV("%s: stream %d all pending buffers have been returned.",
125 __FUNCTION__, stream_id);
126 }
127 }
128 }
129
130 tracker_request_condition_.notify_one();
131 return OK;
132 }
133
TrackReturnedAcquiredBuffers(const std::vector<StreamBuffer> & returned_buffers)134 status_t PendingRequestsTracker::TrackReturnedAcquiredBuffers(
135 const std::vector<StreamBuffer>& returned_buffers) {
136 ATRACE_CALL();
137
138 {
139 std::lock_guard<std::mutex> lock(pending_acquisition_mutex_);
140 for (auto& buffer : returned_buffers) {
141 int32_t stream_id = OverrideStreamIdForGroup(buffer.stream_id);
142 if (!IsStreamConfigured(stream_id)) {
143 ALOGW("%s: stream %d was not configured.", __FUNCTION__, stream_id);
144 // Continue to track other buffers.
145 continue;
146 }
147
148 if (stream_acquired_buffers_[stream_id] == 0) {
149 if (buffer.status == BufferStatus::kOk) {
150 ALOGE("%s: stream %d should not have any pending acquired buffers.",
151 __FUNCTION__, stream_id);
152 } else {
153 // This may indicate that HAL doesn't intend to process a certain
154 // buffer, so the buffer isn't sent to pipeline and it's not
155 // explicitly allocated and recorded in buffer cache manager.
156 // The buffer still needs to return to framework with an error status
157 // if HAL doesn't process it.
158 ALOGV(
159 "%s: stream %d isn't acquired but returned with buffer status %u",
160 __FUNCTION__, stream_id, buffer.status);
161 }
162 // Continue to track other buffers.
163 continue;
164 }
165
166 stream_acquired_buffers_[stream_id]--;
167 }
168 }
169
170 tracker_acquisition_condition_.notify_one();
171 return OK;
172 }
173
OnBufferCacheFlushed()174 void PendingRequestsTracker::OnBufferCacheFlushed() {
175 std::unique_lock<std::mutex> lock(pending_requests_mutex_);
176 requested_stream_ids_.clear();
177 }
178
DoStreamsHaveEnoughBuffersLocked(const std::vector<StreamBuffer> & buffers) const179 bool PendingRequestsTracker::DoStreamsHaveEnoughBuffersLocked(
180 const std::vector<StreamBuffer>& buffers) const {
181 for (auto& buffer : buffers) {
182 int32_t stream_id = OverrideStreamIdForGroup(buffer.stream_id);
183 if (!IsStreamConfigured(stream_id)) {
184 ALOGE("%s: stream %d was not configured.", __FUNCTION__, stream_id);
185 return false;
186 }
187
188 if (stream_pending_buffers_.at(stream_id) >=
189 stream_max_buffers_.at(stream_id)) {
190 ALOGV("%s: stream %d is not ready. max_buffers=%u", __FUNCTION__,
191 stream_id, stream_max_buffers_.at(stream_id));
192 return false;
193 }
194 }
195
196 return true;
197 }
198
DoesStreamHaveEnoughBuffersToAcquireLocked(int32_t stream_id,uint32_t num_buffers) const199 bool PendingRequestsTracker::DoesStreamHaveEnoughBuffersToAcquireLocked(
200 int32_t stream_id, uint32_t num_buffers) const {
201 if (!IsStreamConfigured(stream_id)) {
202 ALOGE("%s: stream %d was not configured.", __FUNCTION__, stream_id);
203 return false;
204 }
205
206 if (stream_acquired_buffers_.at(stream_id) + num_buffers >
207 stream_max_buffers_.at(stream_id)) {
208 ALOGV("%s: stream %d is not ready. max_buffers=%u", __FUNCTION__, stream_id,
209 stream_max_buffers_.at(stream_id));
210 return false;
211 }
212
213 return true;
214 }
215
UpdateRequestedStreamIdsLocked(const std::vector<StreamBuffer> & requested_buffers,std::vector<int32_t> * first_requested_stream_ids)216 status_t PendingRequestsTracker::UpdateRequestedStreamIdsLocked(
217 const std::vector<StreamBuffer>& requested_buffers,
218 std::vector<int32_t>* first_requested_stream_ids) {
219 if (first_requested_stream_ids == nullptr) {
220 ALOGE("%s: first_requested_stream_ids is nullptr", __FUNCTION__);
221 return BAD_VALUE;
222 }
223
224 for (auto& buffer : requested_buffers) {
225 int32_t stream_id = OverrideStreamIdForGroup(buffer.stream_id);
226 auto stream_id_iter = requested_stream_ids_.find(stream_id);
227 if (stream_id_iter == requested_stream_ids_.end()) {
228 first_requested_stream_ids->push_back(stream_id);
229
230 // Include all stream IDs in the same group in first_requested_stream_ids
231 for (auto& [id_in_group, group_stream_id] : grouped_stream_id_map_) {
232 if (group_stream_id == stream_id) {
233 first_requested_stream_ids->push_back(id_in_group);
234 }
235 }
236 requested_stream_ids_.emplace(stream_id);
237 }
238 }
239
240 return OK;
241 }
242
WaitAndTrackRequestBuffers(const CaptureRequest & request,std::vector<int32_t> * first_requested_stream_ids)243 status_t PendingRequestsTracker::WaitAndTrackRequestBuffers(
244 const CaptureRequest& request,
245 std::vector<int32_t>* first_requested_stream_ids) {
246 ATRACE_CALL();
247
248 if (first_requested_stream_ids == nullptr) {
249 ALOGE("%s: first_requested_stream_ids is nullptr", __FUNCTION__);
250 return BAD_VALUE;
251 }
252
253 std::unique_lock<std::mutex> lock(pending_requests_mutex_);
254 if (!tracker_request_condition_.wait_for(
255 lock, std::chrono::milliseconds(kTrackerTimeoutMs), [this, &request] {
256 return DoStreamsHaveEnoughBuffersLocked(request.output_buffers);
257 })) {
258 ALOGE("%s: Waiting for buffer ready timed out.", __FUNCTION__);
259 return TIMED_OUT;
260 }
261
262 ALOGV("%s: all streams are ready", __FUNCTION__);
263
264 TrackRequestBuffersLocked(request.output_buffers);
265
266 first_requested_stream_ids->clear();
267 status_t res = UpdateRequestedStreamIdsLocked(request.output_buffers,
268 first_requested_stream_ids);
269 if (res != OK) {
270 ALOGE("%s: Updating requested stream ID for output buffers failed: %s(%d)",
271 __FUNCTION__, strerror(-res), res);
272 return res;
273 }
274
275 return OK;
276 }
277
WaitAndTrackAcquiredBuffers(int32_t stream_id,uint32_t num_buffers)278 status_t PendingRequestsTracker::WaitAndTrackAcquiredBuffers(
279 int32_t stream_id, uint32_t num_buffers) {
280 ATRACE_CALL();
281
282 int32_t overridden_stream_id = OverrideStreamIdForGroup(stream_id);
283
284 if (!IsStreamConfigured(overridden_stream_id)) {
285 ALOGW("%s: stream %d was not configured.", __FUNCTION__,
286 overridden_stream_id);
287 // Continue to track other buffers.
288 return BAD_VALUE;
289 }
290
291 std::unique_lock<std::mutex> lock(pending_acquisition_mutex_);
292 if (!tracker_acquisition_condition_.wait_for(
293 lock, std::chrono::milliseconds(kAcquireBufferTimeoutMs),
294 [this, overridden_stream_id, num_buffers] {
295 return DoesStreamHaveEnoughBuffersToAcquireLocked(
296 overridden_stream_id, num_buffers);
297 })) {
298 ALOGW("%s: Waiting to acquire buffer timed out.", __FUNCTION__);
299 return TIMED_OUT;
300 }
301
302 stream_acquired_buffers_[overridden_stream_id] += num_buffers;
303
304 return OK;
305 }
306
TrackBufferAcquisitionFailure(int32_t stream_id,uint32_t num_buffers)307 void PendingRequestsTracker::TrackBufferAcquisitionFailure(int32_t stream_id,
308 uint32_t num_buffers) {
309 int32_t overridden_stream_id = OverrideStreamIdForGroup(stream_id);
310 if (!IsStreamConfigured(overridden_stream_id)) {
311 ALOGW("%s: stream %d was not configured.", __FUNCTION__,
312 overridden_stream_id);
313 // Continue to track other buffers.
314 return;
315 }
316
317 std::unique_lock<std::mutex> lock(pending_acquisition_mutex_);
318 stream_acquired_buffers_[overridden_stream_id] -= num_buffers;
319 }
320
321 } // namespace google_camera_hal
322 } // namespace android
323