1 /*
2 * Copyright (C) 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 #include <cstdint>
18 #include <string>
19 #include <unordered_map>
20
21 #include "perfetto/base/status.h"
22 #include "src/base/test/status_matchers.h"
23 #include "src/trace_redaction/collect_timeline_events.h"
24 #include "src/trace_redaction/find_package_uid.h"
25 #include "src/trace_redaction/redact_sched_events.h"
26 #include "src/trace_redaction/trace_redaction_framework.h"
27 #include "src/trace_redaction/trace_redaction_integration_fixture.h"
28 #include "src/trace_redaction/trace_redactor.h"
29 #include "test/gtest_and_gmock.h"
30
31 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
32 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
33 #include "protos/perfetto/trace/ftrace/sched.pbzero.h"
34 #include "protos/perfetto/trace/trace.pbzero.h"
35 #include "protos/perfetto/trace/trace_packet.pbzero.h"
36
37 namespace perfetto::trace_redaction {
38
39 // >>> SELECT uid
40 // >>> FROM package_list
41 // >>> WHERE package_name='com.Unity.com.unity.multiplayer.samples.coop'
42 //
43 // +-------+
44 // | uid |
45 // +-------+
46 // | 10252 |
47 // +-------+
48 //
49 // >>> SELECT uid, upid, name
50 // >>> FROM process
51 // >>> WHERE uid=10252
52 //
53 // +-------+------+----------------------------------------------+
54 // | uid | upid | name |
55 // +-------+------+----------------------------------------------+
56 // | 10252 | 843 | com.Unity.com.unity.multiplayer.samples.coop |
57 // +-------+------+----------------------------------------------+
58 //
59 // >>> SELECT tid, name
60 // >>> FROM thread
61 // >>> WHERE upid=843 AND name IS NOT NULL
62 //
63 // +------+-----------------+
64 // | tid | name |
65 // +------+-----------------+
66 // | 7120 | Binder:7105_2 |
67 // | 7127 | UnityMain |
68 // | 7142 | Job.worker 0 |
69 // | 7143 | Job.worker 1 |
70 // | 7144 | Job.worker 2 |
71 // | 7145 | Job.worker 3 |
72 // | 7146 | Job.worker 4 |
73 // | 7147 | Job.worker 5 |
74 // | 7148 | Job.worker 6 |
75 // | 7150 | Background Job. |
76 // | 7151 | Background Job. |
77 // | 7167 | UnityGfxDeviceW |
78 // | 7172 | AudioTrack |
79 // | 7174 | FMOD stream thr |
80 // | 7180 | Binder:7105_3 |
81 // | 7184 | UnityChoreograp |
82 // | 7945 | Filter0 |
83 // | 7946 | Filter1 |
84 // | 7947 | Thread-7 |
85 // | 7948 | FMOD mixer thre |
86 // | 7950 | UnityGfxDeviceW |
87 // | 7969 | UnityGfxDeviceW |
88 // +------+-----------------+
89 class RedactSchedSwitchIntegrationTest
90 : public testing::Test,
91 protected TraceRedactionIntegrationFixure {
92 protected:
SetUp()93 void SetUp() override {
94 trace_redactor_.emplace_collect<FindPackageUid>();
95 trace_redactor_.emplace_collect<CollectTimelineEvents>();
96
97 auto* redact_sched_events =
98 trace_redactor_.emplace_transform<RedactSchedEvents>();
99 redact_sched_events->emplace_modifier<ClearComms>();
100 redact_sched_events->emplace_waking_filter<AllowAll>();
101
102 context_.package_name = "com.Unity.com.unity.multiplayer.samples.coop";
103 }
104
105 std::unordered_map<int32_t, std::string> expected_names_ = {
106 {7120, "Binder:7105_2"}, {7127, "UnityMain"},
107 {7142, "Job.worker 0"}, {7143, "Job.worker 1"},
108 {7144, "Job.worker 2"}, {7145, "Job.worker 3"},
109 {7146, "Job.worker 4"}, {7147, "Job.worker 5"},
110 {7148, "Job.worker 6"}, {7150, "Background Job."},
111 {7151, "Background Job."}, {7167, "UnityGfxDeviceW"},
112 {7172, "AudioTrack"}, {7174, "FMOD stream thr"},
113 {7180, "Binder:7105_3"}, {7184, "UnityChoreograp"},
114 {7945, "Filter0"}, {7946, "Filter1"},
115 {7947, "Thread-7"}, {7948, "FMOD mixer thre"},
116 {7950, "UnityGfxDeviceW"}, {7969, "UnityGfxDeviceW"},
117 };
118
119 Context context_;
120 TraceRedactor trace_redactor_;
121 };
122
TEST_F(RedactSchedSwitchIntegrationTest,ClearsNonTargetSwitchComms)123 TEST_F(RedactSchedSwitchIntegrationTest, ClearsNonTargetSwitchComms) {
124 auto result = Redact(trace_redactor_, &context_);
125 ASSERT_OK(result) << result.c_message();
126
127 auto original = LoadOriginal();
128 ASSERT_OK(original) << original.status().c_message();
129
130 auto redacted = LoadRedacted();
131 ASSERT_OK(redacted) << redacted.status().c_message();
132
133 auto redacted_trace_data = LoadRedacted();
134 ASSERT_OK(redacted_trace_data) << redacted.status().c_message();
135
136 protos::pbzero::Trace::Decoder decoder(redacted_trace_data.value());
137
138 for (auto packet = decoder.packet(); packet; ++packet) {
139 protos::pbzero::TracePacket::Decoder packet_decoder(*packet);
140
141 if (!packet_decoder.has_ftrace_events()) {
142 continue;
143 }
144
145 protos::pbzero::FtraceEventBundle::Decoder ftrace_events_decoder(
146 packet_decoder.ftrace_events());
147
148 for (auto event = ftrace_events_decoder.event(); event; ++event) {
149 protos::pbzero::FtraceEvent::Decoder event_decoder(*event);
150
151 if (!event_decoder.has_sched_switch()) {
152 continue;
153 }
154
155 protos::pbzero::SchedSwitchFtraceEvent::Decoder sched_decoder(
156 event_decoder.sched_switch());
157
158 ASSERT_TRUE(sched_decoder.has_next_pid());
159 ASSERT_TRUE(sched_decoder.has_next_comm());
160
161 // If the pid is expected, make sure it has the right now. If it is not
162 // expected, it should be missing.
163 auto next_pid = sched_decoder.next_pid();
164 auto next_comm = expected_names_.find(next_pid);
165
166 if (next_comm == expected_names_.end()) {
167 ASSERT_EQ(sched_decoder.next_comm().size, 0u);
168 } else {
169 ASSERT_EQ(sched_decoder.next_comm().ToStdString(), next_comm->second);
170 }
171
172 ASSERT_TRUE(sched_decoder.has_prev_pid());
173 ASSERT_TRUE(sched_decoder.has_prev_comm());
174
175 auto prev_pid = sched_decoder.prev_pid();
176 auto prev_comm = expected_names_.find(prev_pid);
177
178 if (prev_comm == expected_names_.end()) {
179 ASSERT_EQ(sched_decoder.prev_comm().size, 0u);
180 } else {
181 ASSERT_EQ(sched_decoder.prev_comm().ToStdString(), prev_comm->second);
182 }
183 }
184 }
185 }
186
187 } // namespace perfetto::trace_redaction
188