1 /*
2 * Copyright (C) 2022 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/profiling/perf/perf_producer.h"
18
19 #include <stdint.h>
20 #include <optional>
21
22 #include "perfetto/base/logging.h"
23 #include "test/gtest_and_gmock.h"
24
25 namespace perfetto {
26 namespace profiling {
27 namespace {
28
ShouldReject(pid_t pid,std::string cmdline,const TargetFilter & filter,bool skip_cmd,base::FlatSet<std::string> * additional_cmdlines)29 bool ShouldReject(pid_t pid,
30 std::string cmdline,
31 const TargetFilter& filter,
32 bool skip_cmd,
33 base::FlatSet<std::string>* additional_cmdlines) {
34 return PerfProducer::ShouldRejectDueToFilter(
35 pid, filter, skip_cmd, additional_cmdlines, [cmdline](std::string* out) {
36 *out = cmdline;
37 return true;
38 });
39 }
40
TEST(TargetFilterTest,EmptyFilter)41 TEST(TargetFilterTest, EmptyFilter) {
42 {
43 bool skip_cmd = false;
44 base::FlatSet<std::string> extra_cmds;
45 TargetFilter filter;
46
47 // empty filter allows everything
48 EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
49 EXPECT_FALSE(ShouldReject(77, "/bin/echo", filter, skip_cmd, &extra_cmds));
50 }
51 {
52 bool skip_cmd = false;
53 base::FlatSet<std::string> extra_cmds;
54 TargetFilter filter;
55 filter.exclude_pids.insert(1);
56
57 // allow everything besides the explicit exclusions
58 EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
59 EXPECT_FALSE(ShouldReject(77, "/bin/echo", filter, skip_cmd, &extra_cmds));
60
61 EXPECT_TRUE(ShouldReject(1, "/sbin/init", filter, skip_cmd, &extra_cmds));
62 }
63 }
64
TEST(TargetFilterTest,TargetPids)65 TEST(TargetFilterTest, TargetPids) {
66 bool skip_cmd = false;
67 base::FlatSet<std::string> extra_cmds;
68 TargetFilter filter;
69 filter.pids.insert(32);
70 filter.pids.insert(42);
71
72 EXPECT_FALSE(ShouldReject(32, "/bin/echo", filter, skip_cmd, &extra_cmds));
73 EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
74
75 EXPECT_TRUE(ShouldReject(77, "/bin/echo", filter, skip_cmd, &extra_cmds));
76 }
77
TEST(TargetFilterTest,ExcludePids)78 TEST(TargetFilterTest, ExcludePids) {
79 bool skip_cmd = false;
80 base::FlatSet<std::string> extra_cmds;
81 TargetFilter filter;
82 filter.exclude_pids.insert(32);
83 filter.exclude_pids.insert(42);
84
85 EXPECT_FALSE(ShouldReject(77, "/bin/echo", filter, skip_cmd, &extra_cmds));
86
87 EXPECT_TRUE(ShouldReject(32, "/bin/echo", filter, skip_cmd, &extra_cmds));
88 EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
89 }
90
TEST(TargetFilterTest,TargetCmdlines)91 TEST(TargetFilterTest, TargetCmdlines) {
92 {
93 bool skip_cmd = false;
94 base::FlatSet<std::string> extra_cmds;
95 TargetFilter filter;
96 filter.cmdlines.emplace_back("echo");
97 filter.cmdlines.emplace_back("/bin/cat");
98
99 EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
100 EXPECT_FALSE(ShouldReject(42, "/bin/cat", filter, skip_cmd, &extra_cmds));
101
102 EXPECT_TRUE(ShouldReject(42, "/bin/top", filter, skip_cmd, &extra_cmds));
103 }
104 {
105 bool skip_cmd = true;
106 base::FlatSet<std::string> extra_cmds;
107 TargetFilter filter;
108 filter.cmdlines.emplace_back("echo");
109 filter.cmdlines.emplace_back("/bin/cat");
110
111 // As above but with |skip_cmd| making none of the cmdline checks apply.
112 // Therefore everything gets rejected because it's still considered to be a
113 // filter that only requested specific targets (and none of these match).
114 EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
115 EXPECT_TRUE(ShouldReject(42, "/bin/cat", filter, skip_cmd, &extra_cmds));
116 EXPECT_TRUE(ShouldReject(42, "/bin/top", filter, skip_cmd, &extra_cmds));
117 }
118 }
119
TEST(TargetFilterTest,ExcludeCmdlines)120 TEST(TargetFilterTest, ExcludeCmdlines) {
121 bool skip_cmd = false;
122 base::FlatSet<std::string> extra_cmds;
123 TargetFilter filter;
124 filter.exclude_cmdlines.emplace_back("echo");
125 filter.exclude_cmdlines.emplace_back("/bin/cat");
126
127 EXPECT_FALSE(ShouldReject(42, "/bin/top", filter, skip_cmd, &extra_cmds));
128
129 EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
130 EXPECT_TRUE(ShouldReject(42, "/bin/cat", filter, skip_cmd, &extra_cmds));
131 }
132
TEST(TargetFilterTest,ExclusionPrioritised)133 TEST(TargetFilterTest, ExclusionPrioritised) {
134 bool skip_cmd = false;
135 base::FlatSet<std::string> extra_cmds;
136 TargetFilter filter;
137 filter.pids.insert(42);
138 filter.exclude_pids.insert(42);
139 filter.cmdlines.push_back("echo");
140 filter.exclude_cmdlines.push_back("echo");
141
142 EXPECT_TRUE(ShouldReject(42, "/bin/cat", filter, skip_cmd, &extra_cmds));
143 EXPECT_TRUE(ShouldReject(100, "/bin/echo", filter, skip_cmd, &extra_cmds));
144 }
145
TEST(TargetFilterTest,ProcessSharding)146 TEST(TargetFilterTest, ProcessSharding) {
147 {
148 bool skip_cmd = false;
149 base::FlatSet<std::string> extra_cmds;
150 TargetFilter filter;
151 filter.process_sharding =
152 ProcessSharding{/*shard_count=*/4, /*chosen_shard=*/1};
153
154 EXPECT_FALSE(ShouldReject(1, "/bin/echo", filter, skip_cmd, &extra_cmds));
155 EXPECT_FALSE(ShouldReject(41, "/bin/echo", filter, skip_cmd, &extra_cmds));
156
157 EXPECT_TRUE(ShouldReject(0, "/bin/echo", filter, skip_cmd, &extra_cmds));
158 EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
159 }
160 {
161 // as above but with an explicit exclude_pid
162 bool skip_cmd = false;
163 base::FlatSet<std::string> extra_cmds;
164 TargetFilter filter;
165 filter.exclude_pids.insert(41);
166 filter.process_sharding =
167 ProcessSharding{/*shard_count=*/4, /*chosen_shard=*/1};
168
169 EXPECT_FALSE(ShouldReject(1, "/bin/echo", filter, skip_cmd, &extra_cmds));
170
171 // explicit exclusion applies even if pid is in the accepted shard
172 EXPECT_TRUE(ShouldReject(41, "/bin/echo", filter, skip_cmd, &extra_cmds));
173 EXPECT_TRUE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
174 }
175 }
176
TEST(TargetFilterTest,AdditionalCmdlines)177 TEST(TargetFilterTest, AdditionalCmdlines) {
178 bool skip_cmd = false;
179 base::FlatSet<std::string> extra_cmds;
180 TargetFilter filter;
181 filter.additional_cmdline_count = 2;
182
183 // first two distinct cmdlines remembered and allowed:
184 EXPECT_FALSE(ShouldReject(42, "/bin/echo", filter, skip_cmd, &extra_cmds));
185 EXPECT_FALSE(ShouldReject(43, "/bin/echo", filter, skip_cmd, &extra_cmds));
186 EXPECT_FALSE(ShouldReject(44, "/bin/cat", filter, skip_cmd, &extra_cmds));
187
188 // further cmdlines rejected:
189 EXPECT_TRUE(ShouldReject(45, "/bin/top", filter, skip_cmd, &extra_cmds));
190
191 // remembered cmdlines still allowed:
192 EXPECT_FALSE(ShouldReject(46, "/bin/echo", filter, skip_cmd, &extra_cmds));
193
194 EXPECT_EQ(extra_cmds.size(), 2u);
195 EXPECT_EQ(extra_cmds.count("/bin/echo"), 1u);
196 EXPECT_EQ(extra_cmds.count("/bin/cat"), 1u);
197 EXPECT_EQ(extra_cmds.count("/bin/top"), 0u);
198 }
199
200 } // namespace
201 } // namespace profiling
202 } // namespace perfetto
203