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