1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "buffer_loop_tracking.h"
17 #include "buffer_manager.h"
18
19 namespace OHOS::Camera {
TrackingNode(std::string name)20 TrackingNode::TrackingNode(std::string name)
21 {
22 nodeName_ = name;
23 }
24
~TrackingNode()25 TrackingNode::~TrackingNode()
26 {
27 {
28 std::lock_guard<std::mutex> l(lock_);
29 trackingBufferList_.clear();
30 }
31 }
32
GetNodeName() const33 std::string TrackingNode::GetNodeName() const
34 {
35 return nodeName_;
36 }
37
FindTrackingBuffer(const std::shared_ptr<TrackingBuffer> & buffer)38 std::shared_ptr<TrackingBuffer> TrackingNode::FindTrackingBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
39 {
40 if (buffer == nullptr) {
41 return nullptr;
42 }
43
44 std::lock_guard<std::mutex> l(lock_);
45 auto it = std::find_if(trackingBufferList_.begin(), trackingBufferList_.end(),
46 [&buffer](const std::shared_ptr<TrackingBuffer>& b) {
47 return b->GetFrameNumber() == buffer->GetFrameNumber();
48 });
49 if (it == trackingBufferList_.end()) {
50 return nullptr;
51 }
52 return *it;
53 }
54
AttachTrackingBuffer(const std::shared_ptr<TrackingBuffer> & buffer)55 void TrackingNode::AttachTrackingBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
56 {
57 {
58 std::lock_guard<std::mutex> l(lock_);
59 trackingBufferList_.emplace_back(buffer);
60 }
61
62 return;
63 }
64
DetachTrackingBuffer(const std::shared_ptr<TrackingBuffer> & buffer)65 void TrackingNode::DetachTrackingBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
66 {
67 {
68 std::lock_guard<std::mutex> l(lock_);
69 auto it = std::find_if(trackingBufferList_.begin(), trackingBufferList_.end(),
70 [&buffer](const std::shared_ptr<TrackingBuffer>& b) {
71 return b->GetFrameNumber() == buffer->GetFrameNumber();
72 });
73 if (it != trackingBufferList_.end()) {
74 trackingBufferList_.erase(it);
75 }
76 }
77
78 return;
79 }
80
IsEmpty()81 bool TrackingNode::IsEmpty()
82 {
83 std::lock_guard<std::mutex> l(lock_);
84 return trackingBufferList_.empty();
85 }
86
TrackingStream(const int32_t id)87 TrackingStream::TrackingStream(const int32_t id)
88 {
89 trackingId_ = id;
90 }
91
~TrackingStream()92 TrackingStream::~TrackingStream()
93 {
94 {
95 std::lock_guard<std::mutex> l(lock_);
96 trackingNodeList_.clear();
97 CAMERA_LOGD("dtor TrackingStream %{public}p", this);
98 }
99 }
100
GetTrackingStreamId() const101 int32_t TrackingStream::GetTrackingStreamId() const
102 {
103 return trackingId_;
104 }
105
FindTrackingNode(const std::string node)106 std::shared_ptr<TrackingNode> TrackingStream::FindTrackingNode(const std::string node)
107 {
108 std::lock_guard<std::mutex> l(lock_);
109 auto it = std::find_if(trackingNodeList_.begin(), trackingNodeList_.end(),
110 [&node](const std::shared_ptr<TrackingNode>& n) { return n->GetNodeName() == node; });
111 if (it != trackingNodeList_.end()) {
112 return *it;
113 }
114
115 return nullptr;
116 }
117
AttachTrackingNode(const std::shared_ptr<TrackingNode> & node)118 void TrackingStream::AttachTrackingNode(const std::shared_ptr<TrackingNode>& node)
119 {
120 if (FindTrackingNode(node->GetNodeName()) != nullptr) {
121 return;
122 }
123
124 {
125 std::lock_guard<std::mutex> l(lock_);
126 trackingNodeList_.emplace_back(node);
127 }
128
129 return;
130 }
131
DetachTrackingNode(const std::shared_ptr<TrackingNode> & node)132 void TrackingStream::DetachTrackingNode(const std::shared_ptr<TrackingNode>& node)
133 {
134 auto n = FindTrackingNode(node->GetNodeName());
135 if (n == nullptr) {
136 return;
137 }
138
139 {
140 std::lock_guard<std::mutex> l(lock_);
141 auto it = std::find(trackingNodeList_.begin(), trackingNodeList_.end(), node);
142 if (it != trackingNodeList_.end()) {
143 trackingNodeList_.erase(it);
144 }
145 }
146
147 return;
148 }
149
LocateBuffer(const std::shared_ptr<TrackingBuffer> & buffer)150 std::shared_ptr<TrackingNode> TrackingStream::LocateBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
151 {
152 {
153 std::lock_guard<std::mutex> l(lock_);
154 for (auto& n : trackingNodeList_) {
155 if (n == nullptr) {
156 CAMERA_LOGE("fatal error, tracking node list is corrupt.");
157 return nullptr;
158 }
159 if (n->IsEmpty()) {
160 continue;
161 }
162 if (n->FindTrackingBuffer(buffer) != nullptr) {
163 return n;
164 }
165 }
166 return nullptr;
167 }
168 }
169
MoveBuffer(std::shared_ptr<TrackingBuffer> & buffer,std::shared_ptr<TrackingNode> & node)170 void TrackingStream::MoveBuffer(std::shared_ptr<TrackingBuffer>& buffer, std::shared_ptr<TrackingNode>& node)
171 {
172 if (node == nullptr) {
173 CAMERA_LOGE("node is null, cannot track");
174 return;
175 }
176 auto dest = FindTrackingNode(node->GetNodeName());
177 if (dest == nullptr) {
178 CAMERA_LOGE("node %{public}s doesn't being tracked", node->GetNodeName().c_str());
179 return;
180 }
181
182 {
183 std::lock_guard<std::mutex> tl(traceLock_);
184 auto src = LocateBuffer(buffer);
185 if (src != nullptr) {
186 src->DetachTrackingBuffer(buffer);
187 }
188
189 dest->AttachTrackingBuffer(buffer);
190 }
191 return;
192 }
193
RemoveBuffer(std::shared_ptr<TrackingBuffer> & buffer)194 void TrackingStream::RemoveBuffer(std::shared_ptr<TrackingBuffer>& buffer)
195 {
196 std::lock_guard<std::mutex> tl(traceLock_);
197 auto src = LocateBuffer(buffer);
198 if (src != nullptr) {
199 src->DetachTrackingBuffer(buffer);
200 }
201
202 return;
203 }
204
DumpTrace(BufferTraceGraph & graph)205 void TrackingStream::DumpTrace(BufferTraceGraph& graph)
206 {
207 graph.clear();
208 std::lock_guard<std::mutex> tl(traceLock_);
209 std::lock_guard<std::mutex> l(lock_);
210 for (auto& n : trackingNodeList_) {
211 if (n == nullptr) {
212 graph.clear();
213 return;
214 }
215 std::list<TrackingBuffer> buffers = {};
216 auto bufferList = n->GetTrackingBuffer();
217 for (const auto& b : bufferList) {
218 if (b == nullptr) {
219 graph.clear();
220 return;
221 }
222 buffers.emplace_back(*b);
223 }
224 graph.emplace_back(std::make_pair(n->GetNodeName(), buffers));
225 }
226
227 return;
228 }
229
FindTrackingNodePath(const std::string beginNode,const std::string endNode)230 std::list<std::shared_ptr<TrackingNode>> TrackingStream::FindTrackingNodePath(const std::string beginNode,
231 const std::string endNode)
232 {
233 std::lock_guard<std::mutex> l(lock_);
234 std::list<std::shared_ptr<TrackingNode>> nodePath = {};
235 bool isInPath = false;
236 for (auto& n : trackingNodeList_) {
237 if (n == nullptr) {
238 return {};
239 }
240 if (n->GetNodeName() == beginNode || n->GetNodeName() == endNode) {
241 if (nodePath.empty()) {
242 isInPath = true;
243 } else {
244 isInPath = false;
245 }
246 nodePath.emplace_back(n);
247 continue;
248 }
249 if (isInPath) {
250 nodePath.emplace_back(n);
251 }
252 }
253 return nodePath;
254 }
255
GetInstance()256 BufferLoopTracking& BufferLoopTracking::GetInstance()
257 {
258 static BufferLoopTracking stalker;
259 return stalker;
260 }
261
~BufferLoopTracking()262 BufferLoopTracking::~BufferLoopTracking()
263 {
264 {
265 std::lock_guard<std::mutex> l(lock_);
266 trackingStreamList_.clear();
267 handler_ = nullptr;
268 }
269 }
270
FindTrackingStream(const int32_t id)271 std::shared_ptr<TrackingStream> BufferLoopTracking::FindTrackingStream(const int32_t id)
272 {
273 std::lock_guard<std::mutex> l(lock_);
274 auto it = std::find_if(
275 trackingStreamList_.begin(), trackingStreamList_.end(),
276 [&id](const std::shared_ptr<TrackingStream>& stream) { return stream->GetTrackingStreamId() == id; });
277 if (it != trackingStreamList_.end()) {
278 return *it;
279 }
280
281 return nullptr;
282 }
283
AddTrackingStreamBegin(const int32_t trackingId,const int64_t poolId)284 void BufferLoopTracking::AddTrackingStreamBegin(const int32_t trackingId, const int64_t poolId)
285 {
286 auto stream = FindTrackingStream(trackingId);
287 if (stream != nullptr) {
288 return;
289 }
290
291 {
292 std::lock_guard<std::mutex> l(lock_);
293 stream = std::make_shared<TrackingStream>(trackingId);
294 trackingStreamList_.emplace_back(stream);
295 CAMERA_LOGD("add tracking stream %{public}d begin", trackingId);
296 }
297
298 auto manager = BufferManager::GetInstance();
299 if (manager == nullptr) {
300 CAMERA_LOGE("can't get buffer manager");
301 return;
302 }
303
304 auto pool = manager->GetBufferPool(poolId);
305 if (pool == nullptr) {
306 CAMERA_LOGE("can't get buffer pool, id = %{public}" PRId64 "", poolId);
307 return;
308 }
309 pool->EnableTracking(trackingId);
310
311 return;
312 }
313
AddTrackingStreamEnd(const int32_t trackingId)314 void BufferLoopTracking::AddTrackingStreamEnd(const int32_t trackingId)
315 {
316 auto stream = FindTrackingStream(trackingId);
317 if (stream == nullptr) {
318 return;
319 }
320 stream->NodeAddComplete();
321 CAMERA_LOGD("add tracking stream %{public}d end", trackingId);
322
323 return;
324 }
325
DeleteTrackingStream(const int32_t trackingId)326 void BufferLoopTracking::DeleteTrackingStream(const int32_t trackingId)
327 {
328 std::lock_guard<std::mutex> l(lock_);
329 auto it = std::find_if(trackingStreamList_.begin(), trackingStreamList_.end(),
330 [&trackingId](const std::shared_ptr<TrackingStream>& stream) {
331 return stream->GetTrackingStreamId() == trackingId;
332 });
333 if (it == trackingStreamList_.end()) {
334 CAMERA_LOGE("stream %{public}d is not being tracked.", trackingId);
335 return;
336 }
337 trackingStreamList_.erase(it);
338
339 return;
340 }
341
AddTrackingNode(const int32_t trackingId,const std::string node)342 void BufferLoopTracking::AddTrackingNode(const int32_t trackingId, const std::string node)
343 {
344 auto stream = FindTrackingStream(trackingId);
345 if (stream == nullptr) {
346 CAMERA_LOGI("can't add node %{public}s to stream %{public}d", node.c_str(), trackingId);
347 return;
348 }
349 auto n = std::make_shared<TrackingNode>(node);
350 return stream->AttachTrackingNode(n);
351 }
352
ReceiveMessage()353 std::shared_ptr<BufferTrackingMessage> BufferLoopTracking::ReceiveMessage()
354 {
355 if (messageQueue_.empty()) {
356 std::unique_lock<std::mutex> l(messageLock_);
357 if (messageQueue_.empty()) {
358 cv_.wait(l, [this] { return !(running_.load() && messageQueue_.empty()); });
359 }
360 }
361
362 if (!running_.load()) {
363 return nullptr;
364 }
365
366 std::shared_ptr<BufferTrackingMessage> message = nullptr;
367 if (!messageQueue_.empty()) {
368 std::unique_lock<std::mutex> l(messageLock_);
369 if (!messageQueue_.empty()) {
370 message = messageQueue_.front();
371 messageQueue_.pop_front();
372 return message;
373 }
374 }
375
376 return message;
377 }
378
SendBufferMovementMessage(const std::shared_ptr<BufferTrackingMessage> & message)379 void BufferLoopTracking::SendBufferMovementMessage(const std::shared_ptr<BufferTrackingMessage>& message)
380 {
381 std::unique_lock<std::mutex> l(messageLock_);
382 messageQueue_.emplace_back(message);
383 cv_.notify_one();
384
385 return;
386 }
387
HandleMessage()388 void BufferLoopTracking::HandleMessage()
389 {
390 auto message = ReceiveMessage();
391 if (message == nullptr) {
392 return;
393 }
394
395 auto stream = FindTrackingStream(message->trackingId);
396 if (stream == nullptr) {
397 CAMERA_LOGE("cannot handle stream %{public}d", message->trackingId);
398 return;
399 }
400
401 if (!stream->IsNodeComplete()) {
402 CAMERA_LOGW("tracking node in stream %{public}d is incomplete", message->trackingId);
403 return;
404 }
405
406 auto buffer = std::make_shared<TrackingBuffer>(message->frameNumber);
407 if (message->isReturnBack) {
408 stream->RemoveBuffer(buffer);
409 CAMERA_LOGI("buffer %{public}" PRIu64 " return back to pool.", message->frameNumber);
410 return;
411 }
412
413 auto node = std::make_shared<TrackingNode>(message->nodeName);
414 stream->MoveBuffer(buffer, node);
415
416 return;
417 }
418
StartTracking()419 void BufferLoopTracking::StartTracking()
420 {
421 handler_ = std::make_unique<std::thread>([this] {
422 prctl(PR_SET_NAME, "buffertracking");
423 do {
424 HandleMessage();
425 } while (running_.load() == true);
426 });
427 if (handler_ == nullptr) {
428 return;
429 }
430 running_ = true;
431 return;
432 }
433
StopTracking()434 void BufferLoopTracking::StopTracking()
435 {
436 running_ = false;
437 cv_.notify_one();
438 handler_->join();
439 return;
440 }
441
IsEmpty(const int32_t id,const std::string node)442 int32_t BufferLoopTracking::IsEmpty(const int32_t id, const std::string node)
443 {
444 auto stream = FindTrackingStream(id);
445 if (stream == nullptr) {
446 CAMERA_LOGI("stream %{public}d doesn't exist", id);
447 return INVALID_TRACKING_ID;
448 }
449 auto n = stream->FindTrackingNode(node);
450 return n->IsEmpty() ? NODE_IS_EMPTY : NODE_IS_NOT_EMPTY;
451 }
452
IsEmpty(const int32_t id,const std::string beginNode,const std::string endNode)453 int32_t BufferLoopTracking::IsEmpty(const int32_t id, const std::string beginNode, const std::string endNode)
454 {
455 auto stream = FindTrackingStream(id);
456 if (stream == nullptr) {
457 CAMERA_LOGI("stream %{public}d doesn't exist", id);
458 return INVALID_TRACKING_ID;
459 }
460 auto nodePath = stream->FindTrackingNodePath(beginNode, endNode);
461 for (auto& n : nodePath) {
462 if (n == nullptr) {
463 continue;
464 }
465 if (n->IsEmpty() != true) {
466 return NODE_IS_NOT_EMPTY;
467 } else {
468 return NODE_IS_EMPTY;
469 }
470 }
471
472 return true;
473 }
474
DumpTrace(const int32_t id,BufferTraceGraph & graph)475 void BufferLoopTracking::DumpTrace(const int32_t id, BufferTraceGraph& graph)
476 {
477 auto stream = FindTrackingStream(id);
478 if (stream == nullptr) {
479 CAMERA_LOGI("stream %{public}d doesn't exist, can't dump trace", id);
480 return;
481 }
482
483 stream->DumpTrace(graph);
484 return;
485 }
486 } // namespace OHOS::Camera
487