1 /*
2 * Copyright 2024 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 // Copied from //external/perfetto/src/shared_lib/test/utils.h
18
19 #ifndef UTILS_H
20 #define UTILS_H
21
22 #include <cassert>
23 #include <condition_variable>
24 #include <cstdint>
25 #include <functional>
26 #include <iterator>
27 #include <memory>
28 #include <mutex>
29 #include <ostream>
30 #include <string>
31 #include <vector>
32
33 #include "gmock/gmock-matchers.h"
34 #include "gmock/gmock-more-matchers.h"
35 #include "gtest/gtest-matchers.h"
36 #include "gtest/gtest.h"
37 #include "perfetto/public/abi/pb_decoder_abi.h"
38 #include "perfetto/public/pb_utils.h"
39 #include "perfetto/public/tracing_session.h"
40
41 // Pretty printer for gtest
42 void PrintTo(const PerfettoPbDecoderField& field, std::ostream*);
43
44 namespace perfetto {
45 namespace shlib {
46 namespace test_utils {
47
48 class WaitableEvent {
49 public:
50 WaitableEvent() = default;
Notify()51 void Notify() {
52 std::unique_lock<std::mutex> lock(m_);
53 notified_ = true;
54 cv_.notify_one();
55 }
WaitForNotification()56 bool WaitForNotification() {
57 std::unique_lock<std::mutex> lock(m_);
58 cv_.wait(lock, [this] { return notified_; });
59 return notified_;
60 }
IsNotified()61 bool IsNotified() {
62 std::unique_lock<std::mutex> lock(m_);
63 return notified_;
64 }
65
66 private:
67 std::mutex m_;
68 std::condition_variable cv_;
69 bool notified_ = false;
70 };
71
72 class TracingSession {
73 public:
74 class Builder {
75 public:
76 Builder() = default;
add_enabled_category(std::string category)77 Builder& add_enabled_category(std::string category) {
78 enabled_categories_.push_back(std::move(category));
79 return *this;
80 }
add_disabled_category(std::string category)81 Builder& add_disabled_category(std::string category) {
82 disabled_categories_.push_back(std::move(category));
83 return *this;
84 }
add_atrace_category(std::string category)85 Builder& add_atrace_category(std::string category) {
86 atrace_categories_.push_back(std::move(category));
87 return *this;
88 }
add_atrace_category_prefer_sdk(std::string category)89 Builder& add_atrace_category_prefer_sdk(std::string category) {
90 atrace_categories_prefer_sdk_.push_back(std::move(category));
91 return *this;
92 }
93 TracingSession Build();
94
95 private:
96 std::vector<std::string> enabled_categories_;
97 std::vector<std::string> disabled_categories_;
98 std::vector<std::string> atrace_categories_;
99 std::vector<std::string> atrace_categories_prefer_sdk_;
100 };
101
102 static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
103
104 TracingSession(TracingSession&&) noexcept;
105
106 ~TracingSession();
107
session()108 struct PerfettoTracingSessionImpl* session() const {
109 return session_;
110 }
111
112 bool FlushBlocking(uint32_t timeout_ms);
113 void WaitForStopped();
114 void StopBlocking();
115 std::vector<uint8_t> ReadBlocking();
116
117 private:
118 TracingSession() = default;
119 struct PerfettoTracingSessionImpl* session_;
120 std::unique_ptr<WaitableEvent> stopped_;
121 };
122
123 template <typename FieldSkipper>
124 class FieldViewBase {
125 public:
126 class Iterator {
127 public:
128 using iterator_category = std::input_iterator_tag;
129 using value_type = const PerfettoPbDecoderField;
130 using pointer = value_type;
131 using reference = value_type;
132 reference operator*() const {
133 struct PerfettoPbDecoder decoder;
134 decoder.read_ptr = read_ptr_;
135 decoder.end_ptr = end_ptr_;
136 struct PerfettoPbDecoderField field;
137 do {
138 field = PerfettoPbDecoderParseField(&decoder);
139 } while (field.status == PERFETTO_PB_DECODER_OK &&
140 skipper_.ShouldSkip(field));
141 return field;
142 }
143 Iterator& operator++() {
144 struct PerfettoPbDecoder decoder;
145 decoder.read_ptr = read_ptr_;
146 decoder.end_ptr = end_ptr_;
147 PerfettoPbDecoderSkipField(&decoder);
148 read_ptr_ = decoder.read_ptr;
149 AdvanceToFirstInterestingField();
150 return *this;
151 }
152 Iterator operator++(int) {
153 Iterator tmp = *this;
154 ++(*this);
155 return tmp;
156 }
157
158 friend bool operator==(const Iterator& a, const Iterator& b) {
159 return a.read_ptr_ == b.read_ptr_;
160 }
161 friend bool operator!=(const Iterator& a, const Iterator& b) {
162 return a.read_ptr_ != b.read_ptr_;
163 }
164
165 private:
Iterator(const uint8_t * read_ptr,const uint8_t * end_ptr,const FieldSkipper & skipper)166 Iterator(const uint8_t* read_ptr, const uint8_t* end_ptr,
167 const FieldSkipper& skipper)
168 : read_ptr_(read_ptr), end_ptr_(end_ptr), skipper_(skipper) {
169 AdvanceToFirstInterestingField();
170 }
AdvanceToFirstInterestingField()171 void AdvanceToFirstInterestingField() {
172 struct PerfettoPbDecoder decoder;
173 decoder.read_ptr = read_ptr_;
174 decoder.end_ptr = end_ptr_;
175 struct PerfettoPbDecoderField field;
176 const uint8_t* prev_read_ptr;
177 do {
178 prev_read_ptr = decoder.read_ptr;
179 field = PerfettoPbDecoderParseField(&decoder);
180 } while (field.status == PERFETTO_PB_DECODER_OK &&
181 skipper_.ShouldSkip(field));
182 if (field.status == PERFETTO_PB_DECODER_OK) {
183 read_ptr_ = prev_read_ptr;
184 } else {
185 read_ptr_ = decoder.read_ptr;
186 }
187 }
188 friend class FieldViewBase<FieldSkipper>;
189 const uint8_t* read_ptr_;
190 const uint8_t* end_ptr_;
191 const FieldSkipper& skipper_;
192 };
193 using value_type = const PerfettoPbDecoderField;
194 using const_iterator = Iterator;
195 template <typename... Args>
FieldViewBase(const uint8_t * begin,const uint8_t * end,Args...args)196 explicit FieldViewBase(const uint8_t* begin, const uint8_t* end, Args... args)
197 : begin_(begin), end_(end), s_(args...) {
198 }
199 template <typename... Args>
FieldViewBase(const std::vector<uint8_t> & data,Args...args)200 explicit FieldViewBase(const std::vector<uint8_t>& data, Args... args)
201 : FieldViewBase(data.data(), data.data() + data.size(), args...) {
202 }
203 template <typename... Args>
FieldViewBase(const struct PerfettoPbDecoderField & field,Args...args)204 explicit FieldViewBase(const struct PerfettoPbDecoderField& field,
205 Args... args)
206 : s_(args...) {
207 if (field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) {
208 abort();
209 }
210 begin_ = field.value.delimited.start;
211 end_ = begin_ + field.value.delimited.len;
212 }
begin()213 Iterator begin() const {
214 return Iterator(begin_, end_, s_);
215 }
end()216 Iterator end() const {
217 return Iterator(end_, end_, s_);
218 }
front()219 PerfettoPbDecoderField front() const {
220 return *begin();
221 }
222
size()223 size_t size() const {
224 size_t count = 0;
225 for (auto field : *this) {
226 (void)field;
227 count++;
228 }
229 return count;
230 }
231
ok()232 bool ok() const {
233 for (auto field : *this) {
234 if (field.status != PERFETTO_PB_DECODER_OK) {
235 return false;
236 }
237 }
238 return true;
239 }
240
241 private:
242 const uint8_t* begin_;
243 const uint8_t* end_;
244 FieldSkipper s_;
245 };
246
247 // Pretty printer for gtest
248 template <typename FieldSkipper>
PrintTo(const FieldViewBase<FieldSkipper> & field_view,std::ostream * pos)249 void PrintTo(const FieldViewBase<FieldSkipper>& field_view, std::ostream* pos) {
250 std::ostream& os = *pos;
251 os << "{";
252 for (PerfettoPbDecoderField f : field_view) {
253 PrintTo(f, pos);
254 os << ", ";
255 }
256 os << "}";
257 }
258
259 class IdFieldSkipper {
260 public:
IdFieldSkipper(uint32_t id)261 explicit IdFieldSkipper(uint32_t id) : id_(id) {
262 }
IdFieldSkipper(int32_t id)263 explicit IdFieldSkipper(int32_t id) : id_(static_cast<uint32_t>(id)) {
264 }
ShouldSkip(const struct PerfettoPbDecoderField & field)265 bool ShouldSkip(const struct PerfettoPbDecoderField& field) const {
266 return field.id != id_;
267 }
268
269 private:
270 uint32_t id_;
271 };
272
273 class NoFieldSkipper {
274 public:
275 NoFieldSkipper() = default;
ShouldSkip(const struct PerfettoPbDecoderField &)276 bool ShouldSkip(const struct PerfettoPbDecoderField&) const {
277 return false;
278 }
279 };
280
281 // View over all the fields of a contiguous serialized protobuf message.
282 //
283 // Examples:
284 //
285 // for (struct PerfettoPbDecoderField field : FieldView(msg_begin, msg_end)) {
286 // //...
287 // }
288 // FieldView fields2(/*PerfettoPbDecoderField*/ nested_field);
289 // FieldView fields3(/*std::vector<uint8_t>*/ data);
290 // size_t num = fields1.size(); // The number of fields.
291 // bool ok = fields1.ok(); // Checks that the message is not malformed.
292 using FieldView = FieldViewBase<NoFieldSkipper>;
293
294 // Like `FieldView`, but only considers fields with a specific id.
295 //
296 // Examples:
297 //
298 // IdFieldView fields(msg_begin, msg_end, id)
299 using IdFieldView = FieldViewBase<IdFieldSkipper>;
300
301 // Matches a PerfettoPbDecoderField with the specified id. Accepts another
302 // matcher to match the contents of the field.
303 //
304 // Example:
305 // PerfettoPbDecoderField field = ...
306 // EXPECT_THAT(field, PbField(900, VarIntField(5)));
307 template <typename M>
PbField(int32_t id,M m)308 auto PbField(int32_t id, M m) {
309 return testing::AllOf(
310 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
311 testing::Field(&PerfettoPbDecoderField::id, id), m);
312 }
313
314 // Matches a PerfettoPbDecoderField submessage field. Accepts a container
315 // matcher for the subfields.
316 //
317 // Example:
318 // PerfettoPbDecoderField field = ...
319 // EXPECT_THAT(field, MsgField(ElementsAre(...)));
320 template <typename M>
MsgField(M m)321 auto MsgField(M m) {
322 auto f = [](const PerfettoPbDecoderField& field) { return FieldView(field); };
323 return testing::AllOf(
324 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
325 testing::Field(&PerfettoPbDecoderField::wire_type,
326 PERFETTO_PB_WIRE_TYPE_DELIMITED),
327 testing::ResultOf(f, m));
328 }
329
330 // Matches a PerfettoPbDecoderField length delimited field. Accepts a string
331 // matcher.
332 //
333 // Example:
334 // PerfettoPbDecoderField field = ...
335 // EXPECT_THAT(field, StringField("string"));
336 template <typename M>
StringField(M m)337 auto StringField(M m) {
338 auto f = [](const PerfettoPbDecoderField& field) {
339 return std::string(
340 reinterpret_cast<const char*>(field.value.delimited.start),
341 field.value.delimited.len);
342 };
343 return testing::AllOf(
344 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
345 testing::Field(&PerfettoPbDecoderField::wire_type,
346 PERFETTO_PB_WIRE_TYPE_DELIMITED),
347 testing::ResultOf(f, m));
348 }
349
350 // Matches a PerfettoPbDecoderField VarInt field. Accepts an integer matcher
351 //
352 // Example:
353 // PerfettoPbDecoderField field = ...
354 // EXPECT_THAT(field, VarIntField(1)));
355 template <typename M>
VarIntField(M m)356 auto VarIntField(M m) {
357 auto f = [](const PerfettoPbDecoderField& field) {
358 return field.value.integer64;
359 };
360 return testing::AllOf(
361 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
362 testing::Field(&PerfettoPbDecoderField::wire_type,
363 PERFETTO_PB_WIRE_TYPE_VARINT),
364 testing::ResultOf(f, m));
365 }
366
367 // Matches a PerfettoPbDecoderField fixed64 field. Accepts an integer matcher
368 //
369 // Example:
370 // PerfettoPbDecoderField field = ...
371 // EXPECT_THAT(field, Fixed64Field(1)));
372 template <typename M>
Fixed64Field(M m)373 auto Fixed64Field(M m) {
374 auto f = [](const PerfettoPbDecoderField& field) {
375 return field.value.integer64;
376 };
377 return testing::AllOf(
378 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
379 testing::Field(&PerfettoPbDecoderField::wire_type,
380 PERFETTO_PB_WIRE_TYPE_FIXED64),
381 testing::ResultOf(f, m));
382 }
383
384 // Matches a PerfettoPbDecoderField fixed32 field. Accepts an integer matcher
385 //
386 // Example:
387 // PerfettoPbDecoderField field = ...
388 // EXPECT_THAT(field, Fixed32Field(1)));
389 template <typename M>
Fixed32Field(M m)390 auto Fixed32Field(M m) {
391 auto f = [](const PerfettoPbDecoderField& field) {
392 return field.value.integer32;
393 };
394 return testing::AllOf(
395 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
396 testing::Field(&PerfettoPbDecoderField::wire_type,
397 PERFETTO_PB_WIRE_TYPE_FIXED32),
398 testing::ResultOf(f, m));
399 }
400
401 // Matches a PerfettoPbDecoderField double field. Accepts a double matcher
402 //
403 // Example:
404 // PerfettoPbDecoderField field = ...
405 // EXPECT_THAT(field, DoubleField(1.0)));
406 template <typename M>
DoubleField(M m)407 auto DoubleField(M m) {
408 auto f = [](const PerfettoPbDecoderField& field) {
409 return field.value.double_val;
410 };
411 return testing::AllOf(
412 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
413 testing::Field(&PerfettoPbDecoderField::wire_type,
414 PERFETTO_PB_WIRE_TYPE_FIXED64),
415 testing::ResultOf(f, m));
416 }
417
418 // Matches a PerfettoPbDecoderField float field. Accepts a float matcher
419 //
420 // Example:
421 // PerfettoPbDecoderField field = ...
422 // EXPECT_THAT(field, FloatField(1.0)));
423 template <typename M>
FloatField(M m)424 auto FloatField(M m) {
425 auto f = [](const PerfettoPbDecoderField& field) {
426 return field.value.float_val;
427 };
428 return testing::AllOf(
429 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
430 testing::Field(&PerfettoPbDecoderField::wire_type,
431 PERFETTO_PB_WIRE_TYPE_FIXED32),
432 testing::ResultOf(f, m));
433 }
434
435 // Matches a PerfettoPbDecoderField submessage field. Accepts a container
436 // matcher for the subfields.
437 //
438 // Example:
439 // PerfettoPbDecoderField field = ...
440 // EXPECT_THAT(field, AllFieldsWithId(900, ElementsAre(...)));
441 template <typename M>
AllFieldsWithId(int32_t id,M m)442 auto AllFieldsWithId(int32_t id, M m) {
443 auto f = [id](const PerfettoPbDecoderField& field) {
444 return IdFieldView(field, id);
445 };
446 return testing::AllOf(
447 testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
448 testing::Field(&PerfettoPbDecoderField::wire_type,
449 PERFETTO_PB_WIRE_TYPE_DELIMITED),
450 testing::ResultOf(f, m));
451 }
452
453 } // namespace test_utils
454 } // namespace shlib
455 } // namespace perfetto
456
457 #endif // UTILS_H
458