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 }
98 }
99
GetTrackingStreamId() const100 int32_t TrackingStream::GetTrackingStreamId() const
101 {
102 return trackingId_;
103 }
104
FindTrackingNode(const std::string node)105 std::shared_ptr<TrackingNode> TrackingStream::FindTrackingNode(const std::string node)
106 {
107 std::lock_guard<std::mutex> l(lock_);
108 auto it = std::find_if(trackingNodeList_.begin(), trackingNodeList_.end(),
109 [&node](const std::shared_ptr<TrackingNode>& n) { return n->GetNodeName() == node; });
110 if (it != trackingNodeList_.end()) {
111 return *it;
112 }
113
114 return nullptr;
115 }
116
AttachTrackingNode(const std::shared_ptr<TrackingNode> & node)117 void TrackingStream::AttachTrackingNode(const std::shared_ptr<TrackingNode>& node)
118 {
119 if (FindTrackingNode(node->GetNodeName()) != nullptr) {
120 return;
121 }
122
123 {
124 std::lock_guard<std::mutex> l(lock_);
125 trackingNodeList_.emplace_back(node);
126 }
127
128 return;
129 }
130
DetachTrackingNode(const std::shared_ptr<TrackingNode> & node)131 void TrackingStream::DetachTrackingNode(const std::shared_ptr<TrackingNode>& node)
132 {
133 auto n = FindTrackingNode(node->GetNodeName());
134 if (n == nullptr) {
135 return;
136 }
137
138 {
139 std::lock_guard<std::mutex> l(lock_);
140 auto it = std::find(trackingNodeList_.begin(), trackingNodeList_.end(), node);
141 if (it != trackingNodeList_.end()) {
142 trackingNodeList_.erase(it);
143 }
144 }
145
146 return;
147 }
148
LocateBuffer(const std::shared_ptr<TrackingBuffer> & buffer)149 std::shared_ptr<TrackingNode> TrackingStream::LocateBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
150 {
151 {
152 std::lock_guard<std::mutex> l(lock_);
153 for (auto& n : trackingNodeList_) {
154 if (n == nullptr) {
155 CAMERA_LOGE("fatal error, tracking node list is corrupt.");
156 return nullptr;
157 }
158 if (n->IsEmpty()) {
159 continue;
160 }
161 if (n->FindTrackingBuffer(buffer) != nullptr) {
162 return n;
163 }
164 }
165 return nullptr;
166 }
167 }
168
MoveBuffer(std::shared_ptr<TrackingBuffer> & buffer,std::shared_ptr<TrackingNode> & node)169 void TrackingStream::MoveBuffer(std::shared_ptr<TrackingBuffer>& buffer, std::shared_ptr<TrackingNode>& node)
170 {
171 if (node == nullptr) {
172 CAMERA_LOGE("node is null, cannot track");
173 return;
174 }
175 auto dest = FindTrackingNode(node->GetNodeName());
176 if (dest == nullptr) {
177 CAMERA_LOGE("node %{public}s doesn't being tracked", node->GetNodeName().c_str());
178 return;
179 }
180
181 {
182 std::lock_guard<std::mutex> tl(traceLock_);
183 auto src = LocateBuffer(buffer);
184 if (src != nullptr) {
185 src->DetachTrackingBuffer(buffer);
186 }
187
188 dest->AttachTrackingBuffer(buffer);
189 }
190 return;
191 }
192
RemoveBuffer(std::shared_ptr<TrackingBuffer> & buffer)193 void TrackingStream::RemoveBuffer(std::shared_ptr<TrackingBuffer>& buffer)
194 {
195 std::lock_guard<std::mutex> tl(traceLock_);
196 auto src = LocateBuffer(buffer);
197 if (src != nullptr) {
198 src->DetachTrackingBuffer(buffer);
199 }
200
201 return;
202 }
203
DumpTrace(BufferTraceGraph & graph)204 void TrackingStream::DumpTrace(BufferTraceGraph& graph)
205 {
206 graph.clear();
207 std::lock_guard<std::mutex> tl(traceLock_);
208 std::lock_guard<std::mutex> l(lock_);
209 for (auto& n : trackingNodeList_) {
210 if (n == nullptr) {
211 graph.clear();
212 return;
213 }
214 std::list<TrackingBuffer> buffers = {};
215 auto bufferList = n->GetTrackingBuffer();
216 for (const auto& b : bufferList) {
217 if (b == nullptr) {
218 graph.clear();
219 return;
220 }
221 buffers.emplace_back(*b);
222 }
223 graph.emplace_back(std::make_pair(n->GetNodeName(), buffers));
224 }
225
226 return;
227 }
228
FindTrackingNodePath(const std::string beginNode,const std::string endNode)229 std::list<std::shared_ptr<TrackingNode>> TrackingStream::FindTrackingNodePath(const std::string beginNode,
230 const std::string endNode)
231 {
232 std::lock_guard<std::mutex> l(lock_);
233 std::list<std::shared_ptr<TrackingNode>> nodePath = {};
234 bool isInPath = false;
235 for (auto& n : trackingNodeList_) {
236 if (n == nullptr) {
237 return {};
238 }
239 if (n->GetNodeName() == beginNode || n->GetNodeName() == endNode) {
240 if (nodePath.empty()) {
241 isInPath = true;
242 } else {
243 isInPath = false;
244 }
245 nodePath.emplace_back(n);
246 continue;
247 }
248 if (isInPath) {
249 nodePath.emplace_back(n);
250 }
251 }
252 return nodePath;
253 }
254
GetInstance()255 BufferLoopTracking& BufferLoopTracking::GetInstance()
256 {
257 static BufferLoopTracking stalker;
258 return stalker;
259 }
260
~BufferLoopTracking()261 BufferLoopTracking::~BufferLoopTracking()
262 {
263 {
264 std::lock_guard<std::mutex> l(lock_);
265 trackingStreamList_.clear();
266 handler_ = nullptr;
267 }
268 }
269
FindTrackingStream(const int32_t id)270 std::shared_ptr<TrackingStream> BufferLoopTracking::FindTrackingStream(const int32_t id)
271 {
272 std::lock_guard<std::mutex> l(lock_);
273 auto it = std::find_if(
274 trackingStreamList_.begin(), trackingStreamList_.end(),
275 [&id](const std::shared_ptr<TrackingStream>& stream) { return stream->GetTrackingStreamId() == id; });
276 if (it != trackingStreamList_.end()) {
277 return *it;
278 }
279
280 return nullptr;
281 }
282
AddTrackingStreamBegin(const int32_t trackingId,const int64_t poolId)283 void BufferLoopTracking::AddTrackingStreamBegin(const int32_t trackingId, const int64_t poolId)
284 {
285 auto stream = FindTrackingStream(trackingId);
286 if (stream != nullptr) {
287 return;
288 }
289
290 {
291 std::lock_guard<std::mutex> l(lock_);
292 stream = std::make_shared<TrackingStream>(trackingId);
293 if (stream == nullptr) {
294 CAMERA_LOGE("stream is nullptr");
295 return;
296 }
297 trackingStreamList_.emplace_back(stream);
298 CAMERA_LOGD("add tracking stream %{public}d begin", trackingId);
299 }
300
301 auto manager = BufferManager::GetInstance();
302 if (manager == nullptr) {
303 CAMERA_LOGE("can't get buffer manager");
304 return;
305 }
306
307 auto pool = manager->GetBufferPool(poolId);
308 if (pool == nullptr) {
309 CAMERA_LOGE("can't get buffer pool, id = %{public}" PRId64 "", poolId);
310 return;
311 }
312 pool->EnableTracking(trackingId);
313
314 return;
315 }
316
AddTrackingStreamEnd(const int32_t trackingId)317 void BufferLoopTracking::AddTrackingStreamEnd(const int32_t trackingId)
318 {
319 auto stream = FindTrackingStream(trackingId);
320 if (stream == nullptr) {
321 return;
322 }
323 stream->NodeAddComplete();
324 CAMERA_LOGD("add tracking stream %{public}d end", trackingId);
325
326 return;
327 }
328
DeleteTrackingStream(const int32_t trackingId)329 void BufferLoopTracking::DeleteTrackingStream(const int32_t trackingId)
330 {
331 std::lock_guard<std::mutex> l(lock_);
332 auto it = std::find_if(trackingStreamList_.begin(), trackingStreamList_.end(),
333 [&trackingId](const std::shared_ptr<TrackingStream>& stream) {
334 return stream->GetTrackingStreamId() == trackingId;
335 });
336 if (it == trackingStreamList_.end()) {
337 CAMERA_LOGE("stream %{public}d is not being tracked.", trackingId);
338 return;
339 }
340 trackingStreamList_.erase(it);
341
342 return;
343 }
344
AddTrackingNode(const int32_t trackingId,const std::string node)345 void BufferLoopTracking::AddTrackingNode(const int32_t trackingId, const std::string node)
346 {
347 auto stream = FindTrackingStream(trackingId);
348 if (stream == nullptr) {
349 CAMERA_LOGI("can't add node %{public}s to stream %{public}d", node.c_str(), trackingId);
350 return;
351 }
352 auto n = std::make_shared<TrackingNode>(node);
353 if (n == nullptr) {
354 CAMERA_LOGE("n is nullptr");
355 return;
356 }
357 return stream->AttachTrackingNode(n);
358 }
359
ReceiveMessage()360 std::shared_ptr<BufferTrackingMessage> BufferLoopTracking::ReceiveMessage()
361 {
362 if (messageQueue_.empty()) {
363 std::unique_lock<std::mutex> l(messageLock_);
364 if (messageQueue_.empty()) {
365 cv_.wait(l, [this] { return !(running_.load() && messageQueue_.empty()); });
366 }
367 }
368
369 if (!running_.load()) {
370 return nullptr;
371 }
372
373 std::shared_ptr<BufferTrackingMessage> message = nullptr;
374 if (!messageQueue_.empty()) {
375 std::unique_lock<std::mutex> l(messageLock_);
376 if (!messageQueue_.empty()) {
377 message = messageQueue_.front();
378 messageQueue_.pop_front();
379 return message;
380 }
381 }
382
383 return message;
384 }
385
SendBufferMovementMessage(const std::shared_ptr<BufferTrackingMessage> & message)386 void BufferLoopTracking::SendBufferMovementMessage(const std::shared_ptr<BufferTrackingMessage>& message)
387 {
388 std::unique_lock<std::mutex> l(messageLock_);
389 messageQueue_.emplace_back(message);
390 cv_.notify_one();
391
392 return;
393 }
394
HandleMessage()395 void BufferLoopTracking::HandleMessage()
396 {
397 auto message = ReceiveMessage();
398 if (message == nullptr) {
399 return;
400 }
401
402 auto stream = FindTrackingStream(message->trackingId);
403 if (stream == nullptr) {
404 CAMERA_LOGE("cannot handle stream %{public}d", message->trackingId);
405 return;
406 }
407
408 if (!stream->IsNodeComplete()) {
409 CAMERA_LOGW("tracking node in stream %{public}d is incomplete", message->trackingId);
410 return;
411 }
412
413 auto buffer = std::make_shared<TrackingBuffer>(message->frameNumber);
414 if (message->isReturnBack) {
415 stream->RemoveBuffer(buffer);
416 CAMERA_LOGI("buffer %{public}" PRIu64 " return back to pool.", message->frameNumber);
417 return;
418 }
419
420 auto node = std::make_shared<TrackingNode>(message->nodeName);
421 stream->MoveBuffer(buffer, node);
422
423 return;
424 }
425
StartTracking()426 void BufferLoopTracking::StartTracking()
427 {
428 handler_ = std::make_unique<std::thread>([this] {
429 prctl(PR_SET_NAME, "buffertracking");
430 do {
431 HandleMessage();
432 } while (running_.load() == true);
433 });
434 if (handler_ == nullptr) {
435 return;
436 }
437 running_ = true;
438 return;
439 }
440
StopTracking()441 void BufferLoopTracking::StopTracking()
442 {
443 running_ = false;
444 cv_.notify_one();
445 handler_->join();
446 return;
447 }
448
IsEmpty(const int32_t id,const std::string node)449 int32_t BufferLoopTracking::IsEmpty(const int32_t id, const std::string node)
450 {
451 auto stream = FindTrackingStream(id);
452 if (stream == nullptr) {
453 CAMERA_LOGI("stream %{public}d doesn't exist", id);
454 return INVALID_TRACKING_ID;
455 }
456 auto n = stream->FindTrackingNode(node);
457 return n->IsEmpty() ? NODE_IS_EMPTY : NODE_IS_NOT_EMPTY;
458 }
459
IsEmpty(const int32_t id,const std::string beginNode,const std::string endNode)460 int32_t BufferLoopTracking::IsEmpty(const int32_t id, const std::string beginNode, const std::string endNode)
461 {
462 auto stream = FindTrackingStream(id);
463 if (stream == nullptr) {
464 CAMERA_LOGI("stream %{public}d doesn't exist", id);
465 return INVALID_TRACKING_ID;
466 }
467 auto nodePath = stream->FindTrackingNodePath(beginNode, endNode);
468 for (auto& n : nodePath) {
469 if (n == nullptr) {
470 continue;
471 }
472 if (n->IsEmpty() != true) {
473 return NODE_IS_NOT_EMPTY;
474 } else {
475 return NODE_IS_EMPTY;
476 }
477 }
478
479 return true;
480 }
481
DumpTrace(const int32_t id,BufferTraceGraph & graph)482 void BufferLoopTracking::DumpTrace(const int32_t id, BufferTraceGraph& graph)
483 {
484 auto stream = FindTrackingStream(id);
485 if (stream == nullptr) {
486 CAMERA_LOGI("stream %{public}d doesn't exist, can't dump trace", id);
487 return;
488 }
489
490 stream->DumpTrace(graph);
491 return;
492 }
493 } // namespace OHOS::Camera
494