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)28 std::unique_ptr<PendingRequestsTracker> PendingRequestsTracker::Create(
29 const std::vector<HalStream>& hal_configured_streams) {
30 auto tracker =
31 std::unique_ptr<PendingRequestsTracker>(new PendingRequestsTracker());
32 if (tracker == nullptr) {
33 ALOGE("%s: Failed to create PendingRequestsTracker", __FUNCTION__);
34 return nullptr;
35 }
36
37 status_t res = tracker->Initialize(hal_configured_streams);
38 if (res != OK) {
39 ALOGE("%s: Initializing stream buffer tracker failed: %s(%d)", __FUNCTION__,
40 strerror(-res), res);
41 return nullptr;
42 }
43
44 return tracker;
45 }
46
Initialize(const std::vector<HalStream> & hal_configured_streams)47 status_t PendingRequestsTracker::Initialize(
48 const std::vector<HalStream>& hal_configured_streams) {
49 for (auto& hal_stream : hal_configured_streams) {
50 auto [max_buffer_it, max_buffer_inserted] =
51 stream_max_buffers_.emplace(hal_stream.id, hal_stream.max_buffers);
52 if (!max_buffer_inserted) {
53 ALOGE("%s: There are duplicated stream id %d", __FUNCTION__,
54 hal_stream.id);
55 return BAD_VALUE;
56 }
57
58 stream_pending_buffers_.emplace(hal_stream.id, /*pending_buffers=*/0);
59 stream_acquired_buffers_.emplace(hal_stream.id, /*pending_buffers=*/0);
60 }
61
62 return OK;
63 }
64
IsStreamConfigured(int32_t stream_id) const65 bool PendingRequestsTracker::IsStreamConfigured(int32_t stream_id) const {
66 return stream_max_buffers_.find(stream_id) != stream_max_buffers_.end();
67 }
68
TrackRequestBuffersLocked(const std::vector<StreamBuffer> & requested_buffers)69 void PendingRequestsTracker::TrackRequestBuffersLocked(
70 const std::vector<StreamBuffer>& requested_buffers) {
71 ATRACE_CALL();
72
73 for (auto& buffer : requested_buffers) {
74 int32_t stream_id = buffer.stream_id;
75 if (!IsStreamConfigured(stream_id)) {
76 ALOGW("%s: stream %d was not configured.", __FUNCTION__, stream_id);
77 // Continue to track other buffers.
78 continue;
79 }
80
81 stream_pending_buffers_[stream_id]++;
82 }
83 }
84
TrackReturnedResultBuffers(const std::vector<StreamBuffer> & returned_buffers)85 status_t PendingRequestsTracker::TrackReturnedResultBuffers(
86 const std::vector<StreamBuffer>& returned_buffers) {
87 ATRACE_CALL();
88
89 {
90 std::lock_guard<std::mutex> lock(pending_requests_mutex_);
91 for (auto& buffer : returned_buffers) {
92 int32_t stream_id = buffer.stream_id;
93 if (!IsStreamConfigured(stream_id)) {
94 ALOGW("%s: stream %d was not configured.", __FUNCTION__, stream_id);
95 // Continue to track other buffers.
96 continue;
97 }
98
99 if (stream_pending_buffers_[stream_id] == 0) {
100 ALOGE("%s: stream %d should not have any pending quota buffers.",
101 __FUNCTION__, stream_id);
102 // Continue to track other buffers.
103 continue;
104 }
105
106 stream_pending_buffers_[stream_id]--;
107 }
108 }
109
110 tracker_request_condition_.notify_one();
111 return OK;
112 }
113
TrackReturnedAcquiredBuffers(const std::vector<StreamBuffer> & returned_buffers)114 status_t PendingRequestsTracker::TrackReturnedAcquiredBuffers(
115 const std::vector<StreamBuffer>& returned_buffers) {
116 ATRACE_CALL();
117
118 {
119 std::lock_guard<std::mutex> lock(pending_acquisition_mutex_);
120 for (auto& buffer : returned_buffers) {
121 int32_t stream_id = buffer.stream_id;
122 if (!IsStreamConfigured(stream_id)) {
123 ALOGW("%s: stream %d was not configured.", __FUNCTION__, stream_id);
124 // Continue to track other buffers.
125 continue;
126 }
127
128 if (stream_acquired_buffers_[stream_id] == 0) {
129 ALOGE("%s: stream %d should not have any pending acquired buffers.",
130 __FUNCTION__, stream_id);
131 // Continue to track other buffers.
132 continue;
133 }
134
135 stream_acquired_buffers_[stream_id]--;
136 }
137 }
138
139 tracker_acquisition_condition_.notify_one();
140 return OK;
141 }
142
DoStreamsHaveEnoughBuffersLocked(const std::vector<StreamBuffer> & buffers) const143 bool PendingRequestsTracker::DoStreamsHaveEnoughBuffersLocked(
144 const std::vector<StreamBuffer>& buffers) const {
145 for (auto& buffer : buffers) {
146 int32_t stream_id = buffer.stream_id;
147 if (!IsStreamConfigured(stream_id)) {
148 ALOGE("%s: stream %d was not configured.", __FUNCTION__, stream_id);
149 return false;
150 }
151
152 if (stream_pending_buffers_.at(stream_id) >=
153 stream_max_buffers_.at(stream_id)) {
154 ALOGV("%s: stream %d is not ready. max_buffers=%u", __FUNCTION__,
155 stream_id, stream_max_buffers_.at(stream_id));
156 return false;
157 }
158 }
159
160 return true;
161 }
162
DoesStreamHaveEnoughBuffersToAcquireLocked(int32_t stream_id,uint32_t num_buffers) const163 bool PendingRequestsTracker::DoesStreamHaveEnoughBuffersToAcquireLocked(
164 int32_t stream_id, uint32_t num_buffers) const {
165 if (!IsStreamConfigured(stream_id)) {
166 ALOGE("%s: stream %d was not configured.", __FUNCTION__, stream_id);
167 return false;
168 }
169
170 if (stream_acquired_buffers_.at(stream_id) + num_buffers >
171 stream_max_buffers_.at(stream_id)) {
172 ALOGV("%s: stream %d is not ready. max_buffers=%u", __FUNCTION__, stream_id,
173 stream_max_buffers_.at(stream_id));
174 return false;
175 }
176
177 return true;
178 }
179
UpdateRequestedStreamIdsLocked(const std::vector<StreamBuffer> & requested_buffers,std::vector<int32_t> * first_requested_stream_ids)180 status_t PendingRequestsTracker::UpdateRequestedStreamIdsLocked(
181 const std::vector<StreamBuffer>& requested_buffers,
182 std::vector<int32_t>* first_requested_stream_ids) {
183 if (first_requested_stream_ids == nullptr) {
184 ALOGE("%s: first_requested_stream_ids is nullptr", __FUNCTION__);
185 return BAD_VALUE;
186 }
187
188 for (auto& buffer : requested_buffers) {
189 int32_t stream_id = buffer.stream_id;
190 auto stream_id_iter = requested_stream_ids_.find(stream_id);
191 if (stream_id_iter == requested_stream_ids_.end()) {
192 first_requested_stream_ids->push_back(stream_id);
193 requested_stream_ids_.emplace(stream_id);
194 }
195 }
196
197 return OK;
198 }
199
WaitAndTrackRequestBuffers(const CaptureRequest & request,std::vector<int32_t> * first_requested_stream_ids)200 status_t PendingRequestsTracker::WaitAndTrackRequestBuffers(
201 const CaptureRequest& request,
202 std::vector<int32_t>* first_requested_stream_ids) {
203 ATRACE_CALL();
204
205 if (first_requested_stream_ids == nullptr) {
206 ALOGE("%s: first_requested_stream_ids is nullptr", __FUNCTION__);
207 return BAD_VALUE;
208 }
209
210 std::unique_lock<std::mutex> lock(pending_requests_mutex_);
211 if (!tracker_request_condition_.wait_for(
212 lock, std::chrono::milliseconds(kTrackerTimeoutMs), [this, &request] {
213 return DoStreamsHaveEnoughBuffersLocked(request.output_buffers);
214 })) {
215 ALOGE("%s: Waiting for buffer ready timed out.", __FUNCTION__);
216 return TIMED_OUT;
217 }
218
219 ALOGV("%s: all streams are ready", __FUNCTION__);
220
221 TrackRequestBuffersLocked(request.output_buffers);
222
223 first_requested_stream_ids->clear();
224 status_t res = UpdateRequestedStreamIdsLocked(request.output_buffers,
225 first_requested_stream_ids);
226 if (res != OK) {
227 ALOGE("%s: Updating requested stream ID for output buffers failed: %s(%d)",
228 __FUNCTION__, strerror(-res), res);
229 return res;
230 }
231
232 return OK;
233 }
234
WaitAndTrackAcquiredBuffers(int32_t stream_id,uint32_t num_buffers)235 status_t PendingRequestsTracker::WaitAndTrackAcquiredBuffers(
236 int32_t stream_id, uint32_t num_buffers) {
237 ATRACE_CALL();
238
239 if (!IsStreamConfigured(stream_id)) {
240 ALOGW("%s: stream %d was not configured.", __FUNCTION__, stream_id);
241 // Continue to track other buffers.
242 return BAD_VALUE;
243 }
244
245 std::unique_lock<std::mutex> lock(pending_acquisition_mutex_);
246 if (!tracker_acquisition_condition_.wait_for(
247 lock, std::chrono::milliseconds(kAcquireBufferTimeoutMs),
248 [this, stream_id, num_buffers] {
249 return DoesStreamHaveEnoughBuffersToAcquireLocked(stream_id,
250 num_buffers);
251 })) {
252 ALOGW("%s: Waiting to acquire buffer timed out.", __FUNCTION__);
253 return TIMED_OUT;
254 }
255
256 stream_acquired_buffers_[stream_id] += num_buffers;
257
258 return OK;
259 }
260
TrackBufferAcquisitionFailure(int32_t stream_id,uint32_t num_buffers)261 void PendingRequestsTracker::TrackBufferAcquisitionFailure(int32_t stream_id,
262 uint32_t num_buffers) {
263 if (!IsStreamConfigured(stream_id)) {
264 ALOGW("%s: stream %d was not configured.", __FUNCTION__, stream_id);
265 // Continue to track other buffers.
266 return;
267 }
268
269 std::unique_lock<std::mutex> lock(pending_acquisition_mutex_);
270 stream_acquired_buffers_[stream_id] -= num_buffers;
271 }
272
273 } // namespace google_camera_hal
274 } // namespace android
275