1 /*
2 * Copyright (C) 2025 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 #include "test/gtest_and_gmock.h"
18
19 #include "src/android_sdk/perfetto_sdk_for_jni/tracing_sdk.h"
20 #include "src/shared_lib/test/utils.h"
21
22 #include "perfetto/ext/base/string_utils.h"
23
24 #include "protos/perfetto/trace/interned_data/interned_data.gen.h"
25 #include "protos/perfetto/trace/trace.gen.h"
26 #include "protos/perfetto/trace/trace_packet.gen.h"
27 #include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
28 #include "protos/perfetto/trace/track_event/track_event.gen.h"
29
30 namespace perfetto {
31 namespace {
32 using namespace perfetto::shlib::test_utils;
33
34 using protos::gen::DebugAnnotation;
35 using protos::gen::EventCategory;
36 using protos::gen::EventName;
37 using protos::gen::InternedData;
38 using protos::gen::Trace;
39 using protos::gen::TracePacket;
40 using protos::gen::TrackEvent;
41
StartTracing()42 sdk_for_jni::Session StartTracing() {
43 std::vector<uint8_t> build_proto_config =
44 TracingSession::Builder()
45 .set_data_source_name("track_event")
46 .add_enabled_category("*") // enable everything
47 .BuildProtoConfig();
48 return sdk_for_jni::Session(true, build_proto_config.data(),
49 build_proto_config.size());
50 }
51
StopTracing(sdk_for_jni::Session & tracing_session)52 Trace StopTracing(sdk_for_jni::Session& tracing_session) {
53 tracing_session.FlushBlocking(5000);
54 tracing_session.StopBlocking();
55 std::vector trace_data(tracing_session.ReadBlocking());
56 Trace trace;
57 trace.ParseFromArray(trace_data.data(), trace_data.size());
58 return trace;
59 }
60
61 template <class T>
GetNames(const std::vector<T> & items)62 std::vector<std::string> GetNames(const std::vector<T>& items) {
63 std::vector<std::string> names;
64 names.reserve(items.size());
65 for (const auto& item : items) {
66 names.push_back(item.name());
67 }
68 return names;
69 }
70
DebugAnnotationToString(const DebugAnnotation & annotation)71 std::string DebugAnnotationToString(const DebugAnnotation& annotation) {
72 std::stringstream ss;
73 if (annotation.has_int_value()) {
74 ss << "int: " << annotation.int_value();
75 } else if (annotation.has_bool_value()) {
76 ss << "bool: " << annotation.bool_value();
77 } else {
78 ss << "unexpected";
79 }
80 return ss.str();
81 }
82
packet_to_string(const TracePacket & packet)83 std::string packet_to_string(const TracePacket& packet) {
84 std::stringstream ss;
85 ss << "packet {\n";
86 if (packet.has_interned_data()) {
87 ss << "data {";
88 const InternedData& interned_data = packet.interned_data();
89 ss << " categories: ["
90 << base::Join(GetNames(interned_data.event_categories()), ", ") << "]";
91 ss << " names: [" << base::Join(GetNames(interned_data.event_names()), ", ")
92 << "],";
93 ss << " debug_annotation_names: ["
94 << base::Join(GetNames(interned_data.debug_annotation_names()), ", ")
95 << "]";
96 ss << " }\n";
97 }
98 if (packet.has_track_event()) {
99 const TrackEvent& track_event = packet.track_event();
100 ss << "event {";
101 ss << " type: " << track_event.type() << ", ";
102 std::vector<std::string> annotation_values;
103 for (const auto& annotation : track_event.debug_annotations()) {
104 annotation_values.push_back(DebugAnnotationToString(annotation));
105 }
106 ss << "debug_annotations: [" << base::Join(annotation_values, ", ") << "]";
107 ss << " }\n";
108 }
109 ss << "}\n";
110 return ss.str();
111 }
112
TEST(TracingSdkForJniTest,mySimpleTest)113 TEST(TracingSdkForJniTest, mySimpleTest) {
114 sdk_for_jni::register_perfetto(true);
115 sdk_for_jni::Category category("rendering", "", "");
116 category.register_category();
117
118 auto tracing_session = StartTracing();
119
120 // In this test we generate a named slice with an additional payload
121
122 sdk_for_jni::DebugArg<int64_t> player_number_extra("player_number");
123 player_number_extra.set_value(42);
124 sdk_for_jni::DebugArg<bool> player_alive_extra("player_alive");
125 player_alive_extra.set_value(true);
126
127 sdk_for_jni::Extra extra;
128 extra.push_extra(reinterpret_cast<PerfettoTeHlExtra*>(
129 const_cast<PerfettoTeHlExtraDebugArgInt64*>(player_number_extra.get())));
130 extra.push_extra(reinterpret_cast<PerfettoTeHlExtra*>(
131 const_cast<PerfettoTeHlExtraDebugArgBool*>(player_alive_extra.get())));
132 trace_event(PERFETTO_TE_TYPE_SLICE_BEGIN, category.get(), "DrawPlayer",
133 &extra);
134
135 sdk_for_jni::Extra empty_extra;
136 trace_event(PERFETTO_TE_TYPE_SLICE_END, category.get(), "DrawPlayer",
137 &empty_extra);
138
139 Trace trace = StopTracing(tracing_session);
140
141 std::string result;
142 for (const TracePacket& packet : trace.packet()) {
143 if (packet.has_interned_data() || packet.has_track_event()) {
144 result += packet_to_string(packet);
145 }
146 }
147
148 const char* actual = R"(packet {
149 data { categories: [rendering] names: [DrawPlayer], debug_annotation_names: [player_number, player_alive] }
150 event { type: 1, debug_annotations: [int: 42, bool: 1] }
151 }
152 packet {
153 event { type: 2, debug_annotations: [] }
154 }
155 )";
156
157 EXPECT_STREQ(result.c_str(), actual);
158 }
159 } // namespace
160 } // namespace perfetto
161