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
20 #include "perfetto/base/status.h"
21 #include "src/base/test/status_matchers.h"
22 #include "src/trace_redaction/collect_timeline_events.h"
23 #include "src/trace_redaction/scrub_process_stats.h"
24 #include "src/trace_redaction/trace_redaction_framework.h"
25 #include "src/trace_redaction/trace_redaction_integration_fixture.h"
26 #include "src/trace_redaction/trace_redactor.h"
27 #include "test/gtest_and_gmock.h"
28
29 #include "protos/perfetto/trace/ps/process_stats.pbzero.h"
30 #include "protos/perfetto/trace/trace.pbzero.h"
31 #include "protos/perfetto/trace/trace_packet.pbzero.h"
32
33 namespace perfetto::trace_redaction {
34
35 class ScrubProcessStatsTest : public testing::Test,
36 protected TraceRedactionIntegrationFixure {
37 protected:
SetUp()38 void SetUp() override {
39 trace_redactor_.emplace_collect<CollectTimelineEvents>();
40
41 auto* scrub = trace_redactor_.emplace_transform<ScrubProcessStats>();
42 scrub->emplace_filter<ConnectedToPackage>();
43
44 // Package "com.Unity.com.unity.multiplayer.samples.coop";
45 context_.package_uid = 10252;
46 }
47
48 // Gets pids from all process_stats messages in the trace (bytes).
GetAllPids(const std::string & bytes) const49 base::FlatSet<int32_t> GetAllPids(const std::string& bytes) const {
50 base::FlatSet<int32_t> pids;
51
52 protos::pbzero::Trace::Decoder decoder(bytes);
53
54 for (auto packet = decoder.packet(); packet; ++packet) {
55 protos::pbzero::TracePacket::Decoder trace_packet(packet->as_bytes());
56
57 if (!trace_packet.has_process_stats()) {
58 continue;
59 }
60
61 protos::pbzero::ProcessStats::Decoder process_stats(
62 trace_packet.process_stats());
63
64 for (auto process = process_stats.processes(); process; ++process) {
65 protos::pbzero::ProcessStats::Process::Decoder p(process->as_bytes());
66 PERFETTO_DCHECK(p.has_pid());
67 pids.insert(p.pid());
68 }
69 }
70
71 return pids;
72 }
73
74 Context context_;
75 TraceRedactor trace_redactor_;
76 };
77
78 // This test is a canary for changes to the test data. If the test data was to
79 // change, every test in this file would fail.
80 //
81 // SELECT DISTINCT pid
82 // FROM process
83 // WHERE upid IN (
84 // SELECT DISTINCT upid
85 // FROM counter
86 // JOIN process_counter_track ON counter.track_id=process_counter_track.id
87 // WHERE name!='oom_score_adj'
88 // )
89 // ORDER BY pid
90 //
91 // NOTE: WHERE name!='oom_score_adj' is used because there are two sources for
92 // oom_score_adj values and we only want process stats here.
TEST_F(ScrubProcessStatsTest,VerifyTraceStats)93 TEST_F(ScrubProcessStatsTest, VerifyTraceStats) {
94 base::FlatSet<int32_t> expected = {
95 1, 578, 581, 696, 697, 698, 699, 700, 701, 704,
96 709, 710, 718, 728, 749, 750, 751, 752, 756, 760,
97 761, 762, 873, 874, 892, 1046, 1047, 1073, 1074, 1091,
98 1092, 1093, 1101, 1103, 1104, 1105, 1106, 1107, 1110, 1111,
99 1112, 1113, 1115, 1116, 1118, 1119, 1120, 1121, 1123, 1124,
100 1125, 1126, 1127, 1129, 1130, 1131, 1133, 1140, 1145, 1146,
101 1147, 1151, 1159, 1163, 1164, 1165, 1166, 1167, 1168, 1175,
102 1177, 1205, 1206, 1235, 1237, 1238, 1248, 1251, 1254, 1255,
103 1295, 1296, 1298, 1300, 1301, 1303, 1304, 1312, 1317, 1325,
104 1339, 1340, 1363, 1374, 1379, 1383, 1388, 1392, 1408, 1409,
105 1410, 1413, 1422, 1426, 1427, 1428, 1429, 1433, 1436, 1448,
106 1450, 1451, 1744, 1774, 1781, 1814, 2262, 2268, 2286, 2392,
107 2456, 2502, 2510, 2518, 2528, 2569, 3171, 3195, 3262, 3286,
108 3310, 3338, 3442, 3955, 4386, 4759, 5935, 6034, 6062, 6167,
109 6547, 6573, 6720, 6721, 6725, 6944, 6984, 7105, 7207, 7557,
110 7636, 7786, 7874, 7958, 7960, 7967, 15449, 15685, 15697, 16453,
111 19683, 21124, 21839, 23150, 23307, 23876, 24317, 25017, 25126, 25450,
112 25474, 27271, 30604, 32289,
113 };
114
115 auto original = LoadOriginal();
116 ASSERT_OK(original) << original.status().c_message();
117
118 auto actual = GetAllPids(*original);
119
120 for (auto pid : expected) {
121 ASSERT_TRUE(actual.count(pid))
122 << "pid " << pid << " was not found in the trace";
123 }
124
125 for (auto pid : actual) {
126 ASSERT_TRUE(expected.count(pid))
127 << "pid " << pid << " was found in the trace";
128 }
129 }
130
131 // Package name: "com.Unity.com.unity.multiplayer.samples.coop"
132 // Package pid: 7105
TEST_F(ScrubProcessStatsTest,OnlyKeepsStatsForPackage)133 TEST_F(ScrubProcessStatsTest, OnlyKeepsStatsForPackage) {
134 auto result = Redact(trace_redactor_, &context_);
135 ASSERT_OK(result) << result.c_message();
136
137 auto redacted = LoadRedacted();
138 ASSERT_OK(redacted) << redacted.status().c_message();
139
140 auto actual = GetAllPids(*redacted);
141 ASSERT_EQ(actual.size(), 1u);
142 ASSERT_TRUE(actual.count(7105));
143 }
144
145 } // namespace perfetto::trace_redaction
146