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 "src/trace_redaction/redact_process_events.h"
18 #include "src/base/test/status_matchers.h"
19 #include "test/gtest_and_gmock.h"
20
21 #include "protos/perfetto/trace/ftrace/ftrace.gen.h"
22 #include "protos/perfetto/trace/ftrace/ftrace_event.gen.h"
23 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.gen.h"
24 #include "protos/perfetto/trace/ftrace/power.gen.h"
25 #include "protos/perfetto/trace/ftrace/sched.gen.h"
26 #include "protos/perfetto/trace/ftrace/task.gen.h"
27 #include "protos/perfetto/trace/trace.gen.h"
28 #include "protos/perfetto/trace/trace_packet.gen.h"
29
30 namespace perfetto::trace_redaction {
31
32 namespace {
33 constexpr uint64_t kCpu = 1;
34
35 constexpr uint64_t kUidA = 1;
36 constexpr uint64_t kUidB = 2;
37
38 constexpr int32_t kNoParent = 10;
39 constexpr int32_t kPidA = 11;
40 constexpr int32_t kPidB = 12;
41
42 // Used as a child of kPidA.
43 constexpr int32_t kPidAA = kPidA * 10;
44
45 constexpr uint64_t kTimeA = 0;
46 constexpr uint64_t kTimeB = 1000;
47
48 constexpr std::string_view kCommA = "comm-a";
49 constexpr std::string_view kCommB = "comm-b";
50 } // namespace
51
52 class RedactProcessEventsTest : public testing::Test {
53 protected:
SetUp()54 void SetUp() {
55 redact_.emplace_modifier<DoNothing>();
56 redact_.emplace_filter<AllowAll>();
57 }
58
59 RedactProcessEvents redact_;
60 };
61
TEST_F(RedactProcessEventsTest,RejectMissingPackageUid)62 TEST_F(RedactProcessEventsTest, RejectMissingPackageUid) {
63 Context context;
64 context.timeline = std::make_unique<ProcessThreadTimeline>();
65
66 protos::gen::TracePacket packet;
67 auto packet_str = packet.SerializeAsString();
68
69 ASSERT_FALSE(redact_.Transform(context, &packet_str).ok());
70 }
71
TEST_F(RedactProcessEventsTest,RejectMissingTimeline)72 TEST_F(RedactProcessEventsTest, RejectMissingTimeline) {
73 Context context;
74 context.package_uid = kUidA;
75
76 protos::gen::TracePacket packet;
77 auto packet_str = packet.SerializeAsString();
78
79 ASSERT_FALSE(redact_.Transform(context, &packet_str).ok());
80 }
81
TEST_F(RedactProcessEventsTest,RejectMissingPacket)82 TEST_F(RedactProcessEventsTest, RejectMissingPacket) {
83 Context context;
84 context.package_uid = kUidA;
85 context.timeline = std::make_unique<ProcessThreadTimeline>();
86
87 ASSERT_FALSE(redact_.Transform(context, nullptr).ok());
88 }
89
TEST_F(RedactProcessEventsTest,EmptyMissingPacket)90 TEST_F(RedactProcessEventsTest, EmptyMissingPacket) {
91 Context context;
92 context.package_uid = kUidA;
93 context.timeline = std::make_unique<ProcessThreadTimeline>();
94
95 std::string packet_str;
96
97 ASSERT_FALSE(redact_.Transform(context, &packet_str).ok());
98 }
99
100 // Tests which nested messages and fields are removed.
101 class RedactNewTaskTest : public testing::Test {
102 protected:
SetUp()103 void SetUp() override {
104 auto* events = packet_.mutable_ftrace_events();
105 events->set_cpu(kCpu);
106
107 auto* event = events->add_event();
108 event->set_timestamp(kTimeB);
109 event->set_pid(kPidA);
110
111 auto* new_task = event->mutable_task_newtask();
112 new_task->set_clone_flags(0);
113 new_task->set_comm(std::string(kCommA));
114 new_task->set_oom_score_adj(0);
115 new_task->set_pid(kPidA);
116
117 // This test breaks the rules for task_newtask and the timeline. The
118 // timeline will report the task existing before the new task event. This
119 // should not happen in the field, but it makes the test more robust.
120
121 context_.timeline = std::make_unique<ProcessThreadTimeline>();
122
123 context_.timeline->Append(
124 ProcessThreadTimeline::Event::Open(kTimeA, kPidA, kNoParent, kUidA));
125 context_.timeline->Append(
126 ProcessThreadTimeline::Event::Open(kTimeA, kPidB, kNoParent, kUidB));
127 context_.timeline->Sort();
128
129 redact_.emplace_modifier<DoNothing>();
130 redact_.emplace_filter<AllowAll>();
131 }
132
133 RedactProcessEvents redact_;
134 protos::gen::TracePacket packet_;
135 Context context_;
136 };
137
TEST_F(RedactNewTaskTest,KeepCommInPackage)138 TEST_F(RedactNewTaskTest, KeepCommInPackage) {
139 redact_.emplace_modifier<ClearComms>();
140
141 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid A; keep new
142 // task.
143 context_.package_uid = kUidA;
144
145 auto packet_str = packet_.SerializeAsString();
146 ASSERT_OK(redact_.Transform(context_, &packet_str));
147
148 protos::gen::TracePacket packet;
149 ASSERT_TRUE(packet.ParseFromString(packet_str));
150
151 ASSERT_TRUE(packet.has_ftrace_events());
152 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
153
154 const auto& event = packet.ftrace_events().event().at(0);
155 ASSERT_TRUE(event.has_task_newtask());
156
157 const auto& new_task = event.task_newtask();
158
159 ASSERT_TRUE(new_task.has_pid());
160 ASSERT_EQ(new_task.pid(), kPidA);
161
162 ASSERT_TRUE(new_task.has_comm());
163 ASSERT_EQ(new_task.comm(), kCommA);
164 }
165
TEST_F(RedactNewTaskTest,ClearCommOutsidePackage)166 TEST_F(RedactNewTaskTest, ClearCommOutsidePackage) {
167 redact_.emplace_modifier<ClearComms>();
168
169 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid B; clear the
170 // comm.
171 context_.package_uid = kUidB;
172
173 auto packet_str = packet_.SerializeAsString();
174 ASSERT_OK(redact_.Transform(context_, &packet_str));
175
176 protos::gen::TracePacket packet;
177 ASSERT_TRUE(packet.ParseFromString(packet_str));
178
179 ASSERT_TRUE(packet.has_ftrace_events());
180 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
181
182 const auto& event = packet.ftrace_events().event().at(0);
183 ASSERT_TRUE(event.has_task_newtask());
184
185 const auto& new_task = event.task_newtask();
186
187 ASSERT_TRUE(new_task.has_pid());
188 ASSERT_EQ(new_task.pid(), kPidA);
189
190 ASSERT_TRUE(new_task.has_comm());
191 ASSERT_TRUE(new_task.comm().empty());
192 }
193
TEST_F(RedactNewTaskTest,KeepTaskInPackage)194 TEST_F(RedactNewTaskTest, KeepTaskInPackage) {
195 redact_.emplace_filter<ConnectedToPackage>();
196
197 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid A; keep new
198 // task.
199 context_.package_uid = kUidA;
200
201 auto packet_str = packet_.SerializeAsString();
202 ASSERT_OK(redact_.Transform(context_, &packet_str));
203
204 protos::gen::TracePacket packet;
205 ASSERT_TRUE(packet.ParseFromString(packet_str));
206
207 ASSERT_TRUE(packet.has_ftrace_events());
208 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
209
210 const auto& event = packet.ftrace_events().event().at(0);
211 ASSERT_TRUE(event.has_task_newtask());
212
213 const auto& new_task = event.task_newtask();
214
215 ASSERT_TRUE(new_task.has_pid());
216 ASSERT_EQ(new_task.pid(), kPidA);
217 }
218
TEST_F(RedactNewTaskTest,DropTaskOutsidePackage)219 TEST_F(RedactNewTaskTest, DropTaskOutsidePackage) {
220 redact_.emplace_filter<ConnectedToPackage>();
221
222 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid B; drop new
223 // task event.
224 context_.package_uid = kUidB;
225
226 auto packet_str = packet_.SerializeAsString();
227 ASSERT_OK(redact_.Transform(context_, &packet_str));
228
229 protos::gen::TracePacket packet;
230 ASSERT_TRUE(packet.ParseFromString(packet_str));
231
232 ASSERT_TRUE(packet.has_ftrace_events());
233 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
234
235 // The task should have been removed, but the event will still remain.
236 ASSERT_FALSE(packet.ftrace_events().event().at(0).has_task_newtask());
237 }
238
239 class RedactProcessFree : public testing::Test {
240 protected:
SetUp()241 void SetUp() override {
242 auto* events = packet_.mutable_ftrace_events();
243 events->set_cpu(kCpu);
244
245 auto* event = events->add_event();
246 event->set_timestamp(kTimeB);
247 event->set_pid(kPidA);
248
249 auto* process_free = event->mutable_sched_process_free();
250 process_free->set_comm(std::string(kCommA));
251 process_free->set_pid(kPidA);
252 process_free->set_prio(0);
253
254 // By default, this timeline is invalid. sched_process_free would insert
255 // close events. If sched_process_free appended at time B a close event
256 // would be created at time B.
257 //
258 // Timeline spans are inclusive-start but exclusive-end, so a
259 // sched_process_free will never pass a "connected to package" test. The
260 // timeline is created to make testing easier.
261 //
262 // If a test wants a "valid" timeline, it should add a close event at
263 // sched_process_free.
264
265 context_.timeline = std::make_unique<ProcessThreadTimeline>();
266
267 context_.timeline->Append(
268 ProcessThreadTimeline::Event::Open(kTimeA, kPidA, kNoParent, kUidA));
269 context_.timeline->Append(
270 ProcessThreadTimeline::Event::Open(kTimeA, kPidB, kNoParent, kUidB));
271 context_.timeline->Sort();
272
273 redact_.emplace_modifier<DoNothing>();
274 redact_.emplace_filter<AllowAll>();
275 }
276
277 RedactProcessEvents redact_;
278 protos::gen::TracePacket packet_;
279 Context context_;
280 };
281
TEST_F(RedactProcessFree,KeepsCommInPackage)282 TEST_F(RedactProcessFree, KeepsCommInPackage) {
283 redact_.emplace_modifier<ClearComms>();
284
285 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid A; keep comm.
286 context_.package_uid = kUidA;
287
288 auto packet_str = packet_.SerializeAsString();
289 ASSERT_OK(redact_.Transform(context_, &packet_str));
290
291 protos::gen::TracePacket packet;
292 ASSERT_TRUE(packet.ParseFromString(packet_str));
293
294 ASSERT_TRUE(packet.has_ftrace_events());
295 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
296
297 const auto& event = packet.ftrace_events().event().at(0);
298 ASSERT_TRUE(event.has_sched_process_free());
299
300 const auto& process_free = event.sched_process_free();
301
302 ASSERT_TRUE(process_free.has_pid());
303 ASSERT_EQ(process_free.pid(), kPidA);
304
305 ASSERT_TRUE(process_free.has_comm());
306 ASSERT_EQ(process_free.comm(), kCommA);
307 }
308
TEST_F(RedactProcessFree,DropsCommOutsidePackage)309 TEST_F(RedactProcessFree, DropsCommOutsidePackage) {
310 redact_.emplace_modifier<ClearComms>();
311
312 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid B; drop comm.
313 context_.package_uid = kUidB;
314
315 auto packet_str = packet_.SerializeAsString();
316 ASSERT_OK(redact_.Transform(context_, &packet_str));
317
318 protos::gen::TracePacket packet;
319 ASSERT_TRUE(packet.ParseFromString(packet_str));
320
321 ASSERT_TRUE(packet.has_ftrace_events());
322 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
323
324 const auto& event = packet.ftrace_events().event().at(0);
325 ASSERT_TRUE(event.has_sched_process_free());
326
327 const auto& process_free = event.sched_process_free();
328
329 ASSERT_TRUE(process_free.has_pid());
330 ASSERT_EQ(process_free.pid(), kPidA);
331
332 ASSERT_TRUE(process_free.has_comm());
333 ASSERT_TRUE(process_free.comm().empty());
334 }
335
TEST_F(RedactProcessFree,KeepsCommAtProcessFree)336 TEST_F(RedactProcessFree, KeepsCommAtProcessFree) {
337 redact_.emplace_modifier<ClearComms>();
338
339 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid A; Process free
340 // marks the end of Pid A, but process free is inclusive and Pid A is only
341 // free after the event.
342 context_.package_uid = kUidA;
343
344 context_.timeline->Append(ProcessThreadTimeline::Event::Close(kTimeB, kPidA));
345 context_.timeline->Sort();
346
347 auto packet_str = packet_.SerializeAsString();
348 ASSERT_OK(redact_.Transform(context_, &packet_str));
349
350 protos::gen::TracePacket packet;
351 ASSERT_TRUE(packet.ParseFromString(packet_str));
352
353 ASSERT_TRUE(packet.has_ftrace_events());
354 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
355
356 const auto& event = packet.ftrace_events().event().at(0);
357 ASSERT_TRUE(event.has_sched_process_free());
358
359 const auto& process_free = event.sched_process_free();
360
361 ASSERT_TRUE(process_free.has_pid());
362 ASSERT_EQ(process_free.pid(), kPidA);
363
364 ASSERT_TRUE(process_free.has_comm());
365 ASSERT_EQ(process_free.comm(), kCommA);
366 }
367
TEST_F(RedactProcessFree,KeepTaskInPackage)368 TEST_F(RedactProcessFree, KeepTaskInPackage) {
369 redact_.emplace_filter<ConnectedToPackage>();
370
371 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid A; keep new
372 // task.
373 context_.package_uid = kUidA;
374
375 auto packet_str = packet_.SerializeAsString();
376 ASSERT_OK(redact_.Transform(context_, &packet_str));
377
378 protos::gen::TracePacket packet;
379 ASSERT_TRUE(packet.ParseFromString(packet_str));
380
381 ASSERT_TRUE(packet.has_ftrace_events());
382 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
383
384 const auto& event = packet.ftrace_events().event().at(0);
385 ASSERT_TRUE(event.has_sched_process_free());
386
387 const auto& process_free = event.sched_process_free();
388
389 ASSERT_TRUE(process_free.has_pid());
390 ASSERT_EQ(process_free.pid(), kPidA);
391 }
392
TEST_F(RedactProcessFree,DropTaskOutsidePackage)393 TEST_F(RedactProcessFree, DropTaskOutsidePackage) {
394 redact_.emplace_filter<ConnectedToPackage>();
395
396 // The new task is for Pid A. Pid A is part of Uid A. Keep Uid B; drop new
397 // task event.
398 context_.package_uid = kUidB;
399
400 auto packet_str = packet_.SerializeAsString();
401 ASSERT_OK(redact_.Transform(context_, &packet_str));
402
403 protos::gen::TracePacket packet;
404 ASSERT_TRUE(packet.ParseFromString(packet_str));
405
406 ASSERT_TRUE(packet.has_ftrace_events());
407 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
408
409 // The task should have been removed, but the event will still remain.
410 ASSERT_FALSE(packet.ftrace_events().event().at(0).has_sched_process_free());
411 }
412
413 class RedactRenameTest : public testing::Test {
414 protected:
SetUp()415 void SetUp() {
416 auto* events = packet_.mutable_ftrace_events();
417 events->set_cpu(kCpu);
418
419 auto* event = events->add_event();
420 event->set_timestamp(kTimeB);
421 event->set_pid(kPidA);
422
423 // The rename event pid will match the ftrace event pid.
424 auto* rename = event->mutable_task_rename();
425 rename->set_newcomm(std::string(kCommB));
426 rename->set_oldcomm(std::string(kCommA));
427 rename->set_pid(kPidA);
428 rename->set_oom_score_adj(0);
429
430 context_.timeline = std::make_unique<ProcessThreadTimeline>();
431
432 context_.timeline->Append(
433 ProcessThreadTimeline::Event::Open(kTimeA, kPidA, kNoParent, kUidA));
434 context_.timeline->Append(
435 ProcessThreadTimeline::Event::Open(kTimeA, kPidB, kNoParent, kUidB));
436 context_.timeline->Sort();
437
438 redact_.emplace_modifier<DoNothing>();
439 redact_.emplace_filter<AllowAll>();
440 }
441
442 RedactProcessEvents redact_;
443 protos::gen::TracePacket packet_;
444 Context context_;
445 };
446
TEST_F(RedactRenameTest,KeepCommInsidePackage)447 TEST_F(RedactRenameTest, KeepCommInsidePackage) {
448 redact_.emplace_modifier<ClearComms>();
449
450 // The rename task is for Pid A. Pid A is part of Uid A. Keep Uid A; keep
451 // comm.
452 context_.package_uid = kUidA;
453
454 auto packet_str = packet_.SerializeAsString();
455 ASSERT_OK(redact_.Transform(context_, &packet_str));
456
457 protos::gen::TracePacket packet;
458 ASSERT_TRUE(packet.ParseFromString(packet_str));
459
460 ASSERT_TRUE(packet.has_ftrace_events());
461 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
462
463 const auto& event = packet.ftrace_events().event().at(0);
464 ASSERT_TRUE(event.has_task_rename());
465
466 const auto& task_rename = event.task_rename();
467
468 ASSERT_TRUE(task_rename.has_pid());
469 ASSERT_EQ(task_rename.pid(), kPidA);
470
471 ASSERT_TRUE(task_rename.has_oldcomm());
472 ASSERT_EQ(task_rename.oldcomm(), kCommA);
473
474 ASSERT_TRUE(task_rename.has_newcomm());
475 ASSERT_EQ(task_rename.newcomm(), kCommB);
476 }
477
TEST_F(RedactRenameTest,ClearCommOutsidePackage)478 TEST_F(RedactRenameTest, ClearCommOutsidePackage) {
479 redact_.emplace_modifier<ClearComms>();
480
481 // The rename task is for Pid A. Pid A is part of Uid A. Keep Uid B; drop
482 // comm.
483 context_.package_uid = kUidB;
484
485 auto packet_str = packet_.SerializeAsString();
486 ASSERT_OK(redact_.Transform(context_, &packet_str));
487
488 protos::gen::TracePacket packet;
489 ASSERT_TRUE(packet.ParseFromString(packet_str));
490
491 ASSERT_TRUE(packet.has_ftrace_events());
492 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
493
494 const auto& event = packet.ftrace_events().event().at(0);
495 ASSERT_TRUE(event.has_task_rename());
496
497 const auto& task_rename = event.task_rename();
498
499 ASSERT_TRUE(task_rename.has_pid());
500 ASSERT_EQ(task_rename.pid(), kPidA);
501
502 ASSERT_TRUE(task_rename.has_oldcomm());
503 ASSERT_TRUE(task_rename.oldcomm().empty());
504
505 ASSERT_TRUE(task_rename.has_newcomm());
506 ASSERT_TRUE(task_rename.newcomm().empty());
507 }
508
TEST_F(RedactRenameTest,KeepTaskInsidePackage)509 TEST_F(RedactRenameTest, KeepTaskInsidePackage) {
510 redact_.emplace_filter<ConnectedToPackage>();
511
512 // The rename task is for Pid A. Pid A is part of Uid A. Keep Uid A; keep
513 // comm.
514 context_.package_uid = kUidA;
515
516 auto packet_str = packet_.SerializeAsString();
517 ASSERT_OK(redact_.Transform(context_, &packet_str));
518
519 protos::gen::TracePacket packet;
520 ASSERT_TRUE(packet.ParseFromString(packet_str));
521
522 ASSERT_TRUE(packet.has_ftrace_events());
523 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
524
525 const auto& event = packet.ftrace_events().event().at(0);
526 ASSERT_TRUE(event.has_task_rename());
527 }
528
TEST_F(RedactRenameTest,DropTaskOutsidePackage)529 TEST_F(RedactRenameTest, DropTaskOutsidePackage) {
530 redact_.emplace_filter<ConnectedToPackage>();
531
532 // The rename task is for Pid A. Pid A is part of Uid A. Keep Uid B; drop
533 // task.
534 context_.package_uid = kUidB;
535
536 auto packet_str = packet_.SerializeAsString();
537 ASSERT_OK(redact_.Transform(context_, &packet_str));
538
539 protos::gen::TracePacket packet;
540 ASSERT_TRUE(packet.ParseFromString(packet_str));
541
542 ASSERT_TRUE(packet.has_ftrace_events());
543 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
544
545 // The task should have been removed, but the event will still remain.
546 const auto& event = packet.ftrace_events().event().at(0);
547 ASSERT_FALSE(event.has_task_rename());
548 }
549
550 class RedactPrintTest : public testing::Test {
551 protected:
SetUp()552 void SetUp() {
553 auto* events = packet_.mutable_ftrace_events();
554 events->set_cpu(kCpu);
555
556 auto* event = events->add_event();
557 event->set_timestamp(kTimeB);
558 event->set_pid(kPidA);
559
560 // The rename event pid will match the ftrace event pid.
561 auto* print = event->mutable_print();
562 print->set_buf(std::string(kCommA));
563 print->set_ip(0);
564
565 context_.timeline = std::make_unique<ProcessThreadTimeline>();
566
567 context_.timeline->Append(
568 ProcessThreadTimeline::Event::Open(kTimeA, kPidA, kNoParent, kUidA));
569 context_.timeline->Append(
570 ProcessThreadTimeline::Event::Open(kTimeA, kPidB, kNoParent, kUidB));
571 context_.timeline->Sort();
572
573 redact_.emplace_modifier<DoNothing>();
574 redact_.emplace_filter<AllowAll>();
575 }
576
577 RedactProcessEvents redact_;
578 protos::gen::TracePacket packet_;
579 Context context_;
580 };
581
TEST_F(RedactPrintTest,KeepTaskInsidePackage)582 TEST_F(RedactPrintTest, KeepTaskInsidePackage) {
583 redact_.emplace_filter<ConnectedToPackage>();
584
585 // The rename task is for Pid A. Pid A is part of Uid A. Keep Uid A; keep
586 // comm.
587 context_.package_uid = kUidA;
588
589 auto packet_str = packet_.SerializeAsString();
590 ASSERT_OK(redact_.Transform(context_, &packet_str));
591
592 protos::gen::TracePacket packet;
593 ASSERT_TRUE(packet.ParseFromString(packet_str));
594
595 ASSERT_TRUE(packet.has_ftrace_events());
596 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
597
598 const auto& event = packet.ftrace_events().event().at(0);
599 ASSERT_TRUE(event.has_print());
600 }
601
TEST_F(RedactPrintTest,DropTaskOutsidePackage)602 TEST_F(RedactPrintTest, DropTaskOutsidePackage) {
603 redact_.emplace_filter<ConnectedToPackage>();
604
605 // The rename task is for Pid A. Pid A is part of Uid A. Keep Uid B; drop
606 // task.
607 context_.package_uid = kUidB;
608
609 auto packet_str = packet_.SerializeAsString();
610 ASSERT_OK(redact_.Transform(context_, &packet_str));
611
612 protos::gen::TracePacket packet;
613 ASSERT_TRUE(packet.ParseFromString(packet_str));
614
615 ASSERT_TRUE(packet.has_ftrace_events());
616 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
617
618 // The task should have been removed, but the event will still remain.
619 const auto& event = packet.ftrace_events().event().at(0);
620 ASSERT_FALSE(event.has_print());
621 }
622
623 class RedactSuspendResumeTest : public testing::Test {
624 protected:
SetUp()625 void SetUp() {
626 auto* events = packet_.mutable_ftrace_events();
627 events->set_cpu(kCpu);
628
629 for (const auto& action : {"syscore_suspend", "syscore_resume",
630 "timekeeping_freeze", "not-allowed"}) {
631 auto* event = events->add_event();
632 event->set_timestamp(kTimeB);
633 event->set_pid(kPidA);
634
635 auto* suspend_resume = event->mutable_suspend_resume();
636 suspend_resume->set_action(action);
637 suspend_resume->set_start(0);
638 suspend_resume->set_val(3);
639 }
640
641 context_.timeline = std::make_unique<ProcessThreadTimeline>();
642
643 context_.timeline->Append(
644 ProcessThreadTimeline::Event::Open(kTimeA, kPidA, kNoParent, kUidA));
645 context_.timeline->Append(
646 ProcessThreadTimeline::Event::Open(kTimeA, kPidB, kNoParent, kUidB));
647 context_.timeline->Sort();
648
649 redact_.emplace_modifier<DoNothing>();
650 redact_.emplace_filter<AllowAll>();
651 }
652
653 RedactProcessEvents redact_;
654 protos::gen::TracePacket packet_;
655 Context context_;
656 };
657
TEST_F(RedactSuspendResumeTest,KeepTaskInsidePackage)658 TEST_F(RedactSuspendResumeTest, KeepTaskInsidePackage) {
659 redact_.emplace_filter<ConnectedToPackage>();
660
661 context_.package_uid = kUidA;
662
663 auto packet_str = packet_.SerializeAsString();
664 ASSERT_OK(redact_.Transform(context_, &packet_str));
665
666 protos::gen::TracePacket packet;
667 ASSERT_TRUE(packet.ParseFromString(packet_str));
668
669 ASSERT_TRUE(packet.has_ftrace_events());
670 ASSERT_EQ(packet.ftrace_events().event().size(), 4u);
671 }
672
673 // Only actions in the allowlist should be allowed.
674 //
675 // TODO(vaage): The allowlist is not configurable right now. If moved into the
676 // context, it could be configured.
TEST_F(RedactSuspendResumeTest,FiltersByAllowlist)677 TEST_F(RedactSuspendResumeTest, FiltersByAllowlist) {
678 redact_.emplace_filter<ConnectedToPackage>();
679
680 context_.package_uid = kUidA;
681
682 auto packet_str = packet_.SerializeAsString();
683 ASSERT_OK(redact_.Transform(context_, &packet_str));
684
685 protos::gen::TracePacket packet;
686 ASSERT_TRUE(packet.ParseFromString(packet_str));
687
688 ASSERT_TRUE(packet.has_ftrace_events());
689 ASSERT_EQ(packet.ftrace_events().event().size(), 4u);
690
691 {
692 const auto& event = packet.ftrace_events().event().at(0);
693 ASSERT_TRUE(event.has_suspend_resume());
694 ASSERT_EQ(event.suspend_resume().action(), "syscore_suspend");
695 }
696
697 {
698 const auto& event = packet.ftrace_events().event().at(1);
699 ASSERT_TRUE(event.has_suspend_resume());
700 ASSERT_EQ(event.suspend_resume().action(), "syscore_resume");
701 }
702
703 {
704 const auto& event = packet.ftrace_events().event().at(2);
705 ASSERT_TRUE(event.has_suspend_resume());
706 ASSERT_EQ(event.suspend_resume().action(), "timekeeping_freeze");
707 }
708
709 // The fourth entry is an invalid action. While the other entries are valid
710 // and are retained, this one should be dropped.
711 ASSERT_FALSE(packet.ftrace_events().event().at(3).has_suspend_resume());
712 }
713
TEST_F(RedactSuspendResumeTest,DropTaskOutsidePackage)714 TEST_F(RedactSuspendResumeTest, DropTaskOutsidePackage) {
715 redact_.emplace_filter<ConnectedToPackage>();
716
717 context_.package_uid = kUidB;
718
719 auto packet_str = packet_.SerializeAsString();
720 ASSERT_OK(redact_.Transform(context_, &packet_str));
721
722 protos::gen::TracePacket packet;
723 ASSERT_TRUE(packet.ParseFromString(packet_str));
724
725 ASSERT_TRUE(packet.has_ftrace_events());
726 ASSERT_EQ(packet.ftrace_events().event().size(), 4u);
727
728 // The task should have been removed, but the event will still remain.
729 ASSERT_FALSE(packet.ftrace_events().event().at(0).has_suspend_resume());
730 ASSERT_FALSE(packet.ftrace_events().event().at(1).has_suspend_resume());
731 ASSERT_FALSE(packet.ftrace_events().event().at(2).has_suspend_resume());
732 ASSERT_FALSE(packet.ftrace_events().event().at(3).has_suspend_resume());
733 }
734
735 class RedactSchedBlockReasonTest : public testing::Test {
736 protected:
SetUp()737 void SetUp() {
738 auto* events = packet_.mutable_ftrace_events();
739 events->set_cpu(kCpu);
740
741 {
742 auto* event = events->add_event();
743 event->set_timestamp(kTimeB);
744 event->set_pid(kPidB);
745
746 auto* reason = event->mutable_sched_blocked_reason();
747 reason->set_caller(3);
748 reason->set_io_wait(7);
749 reason->set_pid(kPidAA);
750 }
751
752 context_.timeline = std::make_unique<ProcessThreadTimeline>();
753
754 context_.timeline->Append(
755 ProcessThreadTimeline::Event::Open(kTimeA, kPidA, kNoParent, kUidA));
756
757 context_.timeline->Append(
758 ProcessThreadTimeline::Event::Open(kTimeA, kPidAA, kPidA));
759
760 context_.timeline->Append(
761 ProcessThreadTimeline::Event::Open(kTimeA, kPidB, kNoParent, kUidB));
762
763 context_.timeline->Sort();
764
765 redact_.emplace_modifier<DoNothing>();
766 redact_.emplace_filter<AllowAll>();
767 }
768
769 RedactProcessEvents redact_;
770 protos::gen::TracePacket packet_;
771 Context context_;
772 };
773
774 // Implementation detail: No events are removed, only inner messages.
TEST_F(RedactSchedBlockReasonTest,KeepTaskInsidePackage)775 TEST_F(RedactSchedBlockReasonTest, KeepTaskInsidePackage) {
776 redact_.emplace_filter<ConnectedToPackage>();
777
778 // The blocking events target kPidA is connected to kUidA. Since the target is
779 // kUidA, the blocking events should be retained.
780 context_.package_uid = kUidA;
781
782 auto packet_str = packet_.SerializeAsString();
783 ASSERT_OK(redact_.Transform(context_, &packet_str));
784
785 protos::gen::TracePacket packet;
786 ASSERT_TRUE(packet.ParseFromString(packet_str));
787
788 ASSERT_TRUE(packet.has_ftrace_events());
789 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
790
791 // Assumption, event order does not change. The first event was connected to
792 // kUidA.
793 const auto& event = packet.ftrace_events().event().at(0);
794 ASSERT_TRUE(event.has_sched_blocked_reason());
795 ASSERT_EQ(event.sched_blocked_reason().pid(), kPidAA);
796 }
797
798 // Implementation detail: No events are removed, only inner messages.
TEST_F(RedactSchedBlockReasonTest,DropTaskOutsidePackage)799 TEST_F(RedactSchedBlockReasonTest, DropTaskOutsidePackage) {
800 redact_.emplace_filter<ConnectedToPackage>();
801
802 // The blocking events target kPidA is connected to kUidA. Since the target is
803 // kUidB, the blocking events should be dropped.
804 context_.package_uid = kUidB;
805
806 auto packet_str = packet_.SerializeAsString();
807 ASSERT_OK(redact_.Transform(context_, &packet_str));
808
809 protos::gen::TracePacket packet;
810 ASSERT_TRUE(packet.ParseFromString(packet_str));
811
812 ASSERT_TRUE(packet.has_ftrace_events());
813 ASSERT_EQ(packet.ftrace_events().event().size(), 1u);
814
815 // Assumption, event order does not change. The first event was connected to
816 // kUidA.
817 const auto& event = packet.ftrace_events().event().at(0);
818 ASSERT_FALSE(event.has_sched_blocked_reason());
819 }
820
821 } // namespace perfetto::trace_redaction
822