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