• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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/traced/probes/ftrace/ftrace_controller.h"
18 
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 
23 #include "perfetto/ext/base/file_utils.h"
24 #include "src/traced/probes/ftrace/compact_sched.h"
25 #include "src/traced/probes/ftrace/cpu_reader.h"
26 #include "src/traced/probes/ftrace/ftrace_config_muxer.h"
27 #include "src/traced/probes/ftrace/ftrace_config_utils.h"
28 #include "src/traced/probes/ftrace/ftrace_data_source.h"
29 #include "src/traced/probes/ftrace/ftrace_procfs.h"
30 #include "src/traced/probes/ftrace/proto_translation_table.h"
31 #include "src/tracing/core/trace_writer_for_testing.h"
32 #include "test/gtest_and_gmock.h"
33 
34 #include "protos/perfetto/trace/ftrace/ftrace_stats.gen.h"
35 #include "protos/perfetto/trace/ftrace/ftrace_stats.pbzero.h"
36 #include "protos/perfetto/trace/trace_packet.gen.h"
37 #include "protos/perfetto/trace/trace_packet.pbzero.h"
38 
39 using testing::_;
40 using testing::AnyNumber;
41 using testing::ByMove;
42 using testing::ElementsAre;
43 using testing::Invoke;
44 using testing::IsEmpty;
45 using testing::MatchesRegex;
46 using testing::Mock;
47 using testing::NiceMock;
48 using testing::Pair;
49 using testing::Return;
50 using testing::UnorderedElementsAre;
51 
52 using Table = perfetto::ProtoTranslationTable;
53 
54 namespace perfetto {
55 
56 namespace {
57 
58 constexpr char kFooEnablePath[] = "/root/events/group/foo/enable";
59 constexpr char kBarEnablePath[] = "/root/events/group/bar/enable";
60 
PageSizeKb()61 std::string PageSizeKb() {
62   return std::to_string(base::GetSysPageSize() / 1024);
63 }
64 
65 class MockTaskRunner : public base::TaskRunner {
66  public:
67   MOCK_METHOD(void, PostTask, (std::function<void()>), (override));
68   MOCK_METHOD(void,
69               PostDelayedTask,
70               (std::function<void()>, uint32_t delay_ms),
71               (override));
72   MOCK_METHOD(void,
73               AddFileDescriptorWatch,
74               (int fd, std::function<void()>),
75               (override));
76   MOCK_METHOD(void, RemoveFileDescriptorWatch, (int fd), (override));
77   MOCK_METHOD(bool, RunsTasksOnCurrentThread, (), (const, override));
78 };
79 
FakeTable(FtraceProcfs * ftrace)80 std::unique_ptr<Table> FakeTable(FtraceProcfs* ftrace) {
81   std::vector<Field> common_fields;
82   std::vector<Event> events;
83   {
84     events.push_back(Event{});
85     auto& event = events.back();
86     event.name = "foo";
87     event.group = "group";
88     event.ftrace_event_id = 1;
89   }
90   {
91     events.push_back(Event{});
92     auto& event = events.back();
93     event.name = "bar";
94     event.group = "group";
95     event.ftrace_event_id = 10;
96   }
97 
98   return std::unique_ptr<Table>(
99       new Table(ftrace, events, std::move(common_fields),
100                 ProtoTranslationTable::DefaultPageHeaderSpecForTesting(),
101                 InvalidCompactSchedEventFormatForTesting(), PrintkMap()));
102 }
103 
FakeMuxer(FtraceProcfs * ftrace,AtraceWrapper * atrace_wrapper,ProtoTranslationTable * table)104 std::unique_ptr<FtraceConfigMuxer> FakeMuxer(FtraceProcfs* ftrace,
105                                              AtraceWrapper* atrace_wrapper,
106                                              ProtoTranslationTable* table) {
107   return std::unique_ptr<FtraceConfigMuxer>(new FtraceConfigMuxer(
108       ftrace, atrace_wrapper, table, SyscallTable(Architecture::kUnknown), {}));
109 }
110 
111 class MockFtraceProcfs : public FtraceProcfs {
112  public:
MockFtraceProcfs(const std::string & root,size_t cpu_count=1)113   explicit MockFtraceProcfs(const std::string& root, size_t cpu_count = 1)
114       : FtraceProcfs(root) {
115     ON_CALL(*this, NumberOfCpus()).WillByDefault(Return(cpu_count));
116     EXPECT_CALL(*this, NumberOfCpus()).Times(AnyNumber());
117 
118     ON_CALL(*this, ReadFileIntoString(root + "trace_clock"))
119         .WillByDefault(Return("local global [boot]"));
120     EXPECT_CALL(*this, ReadFileIntoString(root + "trace_clock"))
121         .Times(AnyNumber());
122 
123     ON_CALL(*this, ReadFileIntoString(root + "per_cpu/cpu0/stats"))
124         .WillByDefault(Return(""));
125     EXPECT_CALL(*this, ReadFileIntoString(root + "per_cpu/cpu0/stats"))
126         .Times(AnyNumber());
127 
128     ON_CALL(*this, ReadFileIntoString(root + "events//not_an_event/format"))
129         .WillByDefault(Return(""));
130     EXPECT_CALL(*this, ReadFileIntoString(root + "events//not_an_event/format"))
131         .Times(AnyNumber());
132 
133     ON_CALL(*this, ReadFileIntoString(root + "events/group/bar/format"))
134         .WillByDefault(Return(""));
135     EXPECT_CALL(*this, ReadFileIntoString(root + "events/group/bar/format"))
136         .Times(AnyNumber());
137 
138     ON_CALL(*this, WriteToFile(_, _)).WillByDefault(Return(true));
139     ON_CALL(*this, ClearFile(_)).WillByDefault(Return(true));
140 
141     ON_CALL(*this, WriteToFile(root + "tracing_on", _))
142         .WillByDefault(Invoke(this, &MockFtraceProcfs::WriteTracingOn));
143     ON_CALL(*this, ReadOneCharFromFile(root + "tracing_on"))
144         .WillByDefault(Invoke(this, &MockFtraceProcfs::ReadTracingOn));
145     EXPECT_CALL(*this, ReadOneCharFromFile(root + "tracing_on"))
146         .Times(AnyNumber());
147 
148     ON_CALL(*this, WriteToFile(root + "current_tracer", _))
149         .WillByDefault(Invoke(this, &MockFtraceProcfs::WriteCurrentTracer));
150     ON_CALL(*this, ReadFileIntoString(root + "current_tracer"))
151         .WillByDefault(Invoke(this, &MockFtraceProcfs::ReadCurrentTracer));
152     EXPECT_CALL(*this, ReadFileIntoString(root + "current_tracer"))
153         .Times(AnyNumber());
154 
155     ON_CALL(*this, ReadFileIntoString(root + "buffer_percent"))
156         .WillByDefault(Return("50\n"));
157     EXPECT_CALL(*this, ReadFileIntoString(root + "buffer_percent"))
158         .Times(AnyNumber());
159   }
160 
WriteTracingOn(const std::string &,const std::string & value)161   bool WriteTracingOn(const std::string& /*path*/, const std::string& value) {
162     PERFETTO_CHECK(value == "1" || value == "0");
163     tracing_on_ = value == "1";
164     return true;
165   }
166 
ReadTracingOn(const std::string &)167   char ReadTracingOn(const std::string& /*path*/) {
168     return tracing_on_ ? '1' : '0';
169   }
170 
WriteCurrentTracer(const std::string &,const std::string & value)171   bool WriteCurrentTracer(const std::string& /*path*/,
172                           const std::string& value) {
173     current_tracer_ = value;
174     return true;
175   }
176 
ReadCurrentTracer(const std::string &)177   std::string ReadCurrentTracer(const std::string& /*path*/) {
178     return current_tracer_;
179   }
180 
OpenPipeForCpu(size_t)181   base::ScopedFile OpenPipeForCpu(size_t /*cpu*/) override {
182     return base::ScopedFile(base::OpenFile("/dev/null", O_RDONLY));
183   }
184 
185   MOCK_METHOD(bool,
186               WriteToFile,
187               (const std::string& path, const std::string& str),
188               (override));
189   MOCK_METHOD(size_t, NumberOfCpus, (), (const, override));
190   MOCK_METHOD(char, ReadOneCharFromFile, (const std::string& path), (override));
191   MOCK_METHOD(bool, ClearFile, (const std::string& path), (override));
192   MOCK_METHOD(bool, IsFileWriteable, (const std::string& path), (override));
193   MOCK_METHOD(std::string,
194               ReadFileIntoString,
195               (const std::string& path),
196               (const, override));
197 
is_tracing_on()198   bool is_tracing_on() { return tracing_on_; }
199 
200  private:
201   bool tracing_on_ = true;
202   std::string current_tracer_ = "nop";
203 };
204 
205 class MockAtraceWrapper : public AtraceWrapper {
206  public:
207   MOCK_METHOD(bool, RunAtrace, (const std::vector<std::string>&, std::string*));
208   MOCK_METHOD(bool, SupportsUserspaceOnly, ());
209 };
210 
211 }  // namespace
212 
213 class TestFtraceController : public FtraceController,
214                              public FtraceController::Observer {
215  public:
TestFtraceController(std::unique_ptr<MockFtraceProcfs> ftrace_procfs,std::unique_ptr<Table> table,std::unique_ptr<AtraceWrapper> atrace_wrapper,std::unique_ptr<FtraceConfigMuxer> muxer,std::unique_ptr<MockTaskRunner> runner,MockFtraceProcfs * raw_procfs)216   TestFtraceController(std::unique_ptr<MockFtraceProcfs> ftrace_procfs,
217                        std::unique_ptr<Table> table,
218                        std::unique_ptr<AtraceWrapper> atrace_wrapper,
219                        std::unique_ptr<FtraceConfigMuxer> muxer,
220                        std::unique_ptr<MockTaskRunner> runner,
221                        MockFtraceProcfs* raw_procfs)
222       : FtraceController(std::move(ftrace_procfs),
223                          std::move(table),
224                          std::move(atrace_wrapper),
225                          std::move(muxer),
226                          runner.get(),
227                          /*observer=*/this),
228         runner_(std::move(runner)),
229         primary_procfs_(raw_procfs) {}
230 
runner()231   MockTaskRunner* runner() { return runner_.get(); }
procfs()232   MockFtraceProcfs* procfs() { return primary_procfs_; }
tick_period_ms()233   uint32_t tick_period_ms() { return GetTickPeriodMs(); }
234 
AddFakeDataSource(const FtraceConfig & cfg)235   std::unique_ptr<FtraceDataSource> AddFakeDataSource(const FtraceConfig& cfg) {
236     std::unique_ptr<FtraceDataSource> data_source(new FtraceDataSource(
237         GetWeakPtr(), 0 /* session id */, cfg, nullptr /* trace_writer */));
238     if (!AddDataSource(data_source.get()))
239       return nullptr;
240     return data_source;
241   }
242 
NowMs() const243   uint64_t NowMs() const override { return 0; }
OnFtraceDataWrittenIntoDataSourceBuffers()244   void OnFtraceDataWrittenIntoDataSourceBuffers() override {}
245 
InstanceExists(const std::string & instance_name)246   bool InstanceExists(const std::string& instance_name) {
247     auto* instance = GetInstance(instance_name);
248     return instance != nullptr;
249   }
250 
PrepareMockProcfsForInstance(const std::string & name,std::unique_ptr<MockFtraceProcfs> fs)251   void PrepareMockProcfsForInstance(const std::string& name,
252                                     std::unique_ptr<MockFtraceProcfs> fs) {
253     pending_instance_procfs_[name] = std::move(fs);
254   }
255 
GetInstanceMockProcfs(const std::string & instance_name)256   MockFtraceProcfs* GetInstanceMockProcfs(const std::string& instance_name) {
257     auto* instance = GetInstance(instance_name);
258     PERFETTO_CHECK(instance);
259     return reinterpret_cast<MockFtraceProcfs*>(instance->ftrace_procfs.get());
260   }
261 
CreateSecondaryInstance(const std::string & instance_name)262   std::unique_ptr<FtraceInstanceState> CreateSecondaryInstance(
263       const std::string& instance_name) override {
264     auto ftrace_procfs = std::move(pending_instance_procfs_[instance_name]);
265     PERFETTO_CHECK(ftrace_procfs);
266 
267     auto table = FakeTable(ftrace_procfs.get());
268     auto muxer = FakeMuxer(ftrace_procfs.get(), atrace_wrapper(), table.get());
269     return std::unique_ptr<FtraceController::FtraceInstanceState>(
270         new FtraceController::FtraceInstanceState(
271             std::move(ftrace_procfs), std::move(table), std::move(muxer)));
272   }
273 
274  private:
275   TestFtraceController(const TestFtraceController&) = delete;
276   TestFtraceController& operator=(const TestFtraceController&) = delete;
277 
278   std::unique_ptr<MockTaskRunner> runner_;
279   MockFtraceProcfs* primary_procfs_;
280   std::map<std::string, std::unique_ptr<MockFtraceProcfs>>
281       pending_instance_procfs_;
282 };
283 
284 namespace {
285 
CreateTestController(bool procfs_is_nice_mock,size_t cpu_count=1)286 std::unique_ptr<TestFtraceController> CreateTestController(
287     bool procfs_is_nice_mock,
288     size_t cpu_count = 1) {
289   std::unique_ptr<MockTaskRunner> runner =
290       std::unique_ptr<MockTaskRunner>(new NiceMock<MockTaskRunner>());
291 
292   std::unique_ptr<MockFtraceProcfs> ftrace_procfs;
293   if (procfs_is_nice_mock) {
294     ftrace_procfs = std::unique_ptr<MockFtraceProcfs>(
295         new NiceMock<MockFtraceProcfs>("/root/", cpu_count));
296   } else {
297     ftrace_procfs = std::unique_ptr<MockFtraceProcfs>(
298         new MockFtraceProcfs("/root/", cpu_count));
299   }
300 
301   std::unique_ptr<AtraceWrapper> atrace_wrapper;
302 
303   auto table = FakeTable(ftrace_procfs.get());
304 
305   auto muxer =
306       FakeMuxer(ftrace_procfs.get(), atrace_wrapper.get(), table.get());
307 
308   MockFtraceProcfs* raw_procfs = ftrace_procfs.get();
309   return std::unique_ptr<TestFtraceController>(new TestFtraceController(
310       std::move(ftrace_procfs), std::move(table), std::move(atrace_wrapper),
311       std::move(muxer), std::move(runner), raw_procfs));
312 }
313 
314 }  // namespace
315 
TEST(FtraceControllerTest,NonExistentEventsDontCrash)316 TEST(FtraceControllerTest, NonExistentEventsDontCrash) {
317   auto controller = CreateTestController(true /* nice procfs */);
318 
319   FtraceConfig config = CreateFtraceConfig({"not_an_event"});
320   EXPECT_TRUE(controller->AddFakeDataSource(config));
321 }
322 
TEST(FtraceControllerTest,RejectsBadEventNames)323 TEST(FtraceControllerTest, RejectsBadEventNames) {
324   auto controller = CreateTestController(true /* nice procfs */);
325 
326   FtraceConfig config = CreateFtraceConfig({"../try/to/escape"});
327   EXPECT_FALSE(controller->AddFakeDataSource(config));
328   config = CreateFtraceConfig({"/event"});
329   EXPECT_FALSE(controller->AddFakeDataSource(config));
330   config = CreateFtraceConfig({"event/"});
331   EXPECT_FALSE(controller->AddFakeDataSource(config));
332 }
333 
TEST(FtraceControllerTest,OneSink)334 TEST(FtraceControllerTest, OneSink) {
335   auto controller = CreateTestController(false /* nice procfs */);
336 
337   // No read tasks posted as part of adding the data source.
338   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
339 
340   FtraceConfig config = CreateFtraceConfig({"group/foo"});
341 
342   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
343   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
344   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
345       .WillOnce(Return(true));
346   EXPECT_CALL(*controller->procfs(),
347               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
348       .WillRepeatedly(Return(true));
349   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
350   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
351 
352   auto data_source = controller->AddFakeDataSource(config);
353   ASSERT_TRUE(data_source);
354 
355   // Verify that no read tasks have been posted. And set up expectation that
356   // a single recurring read task will be posted as part of starting the data
357   // source.
358   Mock::VerifyAndClearExpectations(controller->runner());
359   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
360       .WillRepeatedly(Return(true));
361 
362   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
363   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
364   ASSERT_TRUE(controller->StartDataSource(data_source.get()));
365 
366   // Verify single posted read task.
367   Mock::VerifyAndClearExpectations(controller->runner());
368 
369   // State clearing on tracing teardown.
370   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
371   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
372   EXPECT_CALL(*controller->procfs(),
373               WriteToFile("/root/buffer_size_kb", PageSizeKb()));
374   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
375   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
376       .WillOnce(Return(true));
377   EXPECT_CALL(*controller->procfs(),
378               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
379       .WillRepeatedly(Return(true));
380   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
381 
382   data_source.reset();
383   EXPECT_TRUE(controller->procfs()->is_tracing_on());
384 }
385 
TEST(FtraceControllerTest,MultipleSinks)386 TEST(FtraceControllerTest, MultipleSinks) {
387   auto controller = CreateTestController(false /* nice procfs */);
388 
389   FtraceConfig configA = CreateFtraceConfig({"group/foo"});
390   FtraceConfig configB = CreateFtraceConfig({"group/foo", "group/bar"});
391 
392   // No read tasks posted as part of adding the data sources.
393   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
394 
395   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
396   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
397   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
398       .WillOnce(Return(true));
399   EXPECT_CALL(*controller->procfs(),
400               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
401       .WillRepeatedly(Return(true));
402   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
403   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
404   auto data_sourceA = controller->AddFakeDataSource(configA);
405   EXPECT_CALL(*controller->procfs(), WriteToFile(kBarEnablePath, "1"));
406   auto data_sourceB = controller->AddFakeDataSource(configB);
407 
408   // Verify that no read tasks have been posted. And set up expectation that
409   // a single recurring read task will be posted as part of starting the data
410   // sources.
411   Mock::VerifyAndClearExpectations(controller->runner());
412   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
413       .WillRepeatedly(Return(true));
414 
415   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
416   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
417   ASSERT_TRUE(controller->StartDataSource(data_sourceA.get()));
418   ASSERT_TRUE(controller->StartDataSource(data_sourceB.get()));
419 
420   // Verify single posted read task.
421   Mock::VerifyAndClearExpectations(controller->runner());
422 
423   data_sourceA.reset();
424   EXPECT_TRUE(controller->procfs()->is_tracing_on());
425 
426   // State clearing on tracing teardown.
427   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
428   EXPECT_CALL(*controller->procfs(), WriteToFile(kBarEnablePath, "0"));
429   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
430   EXPECT_CALL(*controller->procfs(),
431               WriteToFile("/root/buffer_size_kb", PageSizeKb()));
432   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
433   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
434       .WillOnce(Return(true));
435   EXPECT_CALL(*controller->procfs(),
436               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
437       .WillRepeatedly(Return(true));
438   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
439   data_sourceB.reset();
440   EXPECT_TRUE(controller->procfs()->is_tracing_on());
441 }
442 
TEST(FtraceControllerTest,ControllerMayDieFirst)443 TEST(FtraceControllerTest, ControllerMayDieFirst) {
444   auto controller = CreateTestController(false /* nice procfs */);
445 
446   FtraceConfig config = CreateFtraceConfig({"group/foo"});
447 
448   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
449   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
450   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
451       .WillOnce(Return(true));
452   EXPECT_CALL(*controller->procfs(),
453               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
454       .WillRepeatedly(Return(true));
455   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_size_kb", _));
456   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "1"));
457   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
458       .WillRepeatedly(Return(true));
459   auto data_source = controller->AddFakeDataSource(config);
460 
461   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
462   ASSERT_TRUE(controller->StartDataSource(data_source.get()));
463 
464   // State clearing on tracing teardown.
465   EXPECT_CALL(*controller->procfs(), WriteToFile(kFooEnablePath, "0"));
466   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
467   EXPECT_CALL(*controller->procfs(),
468               WriteToFile("/root/buffer_size_kb", PageSizeKb()));
469   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/events/enable", "0"));
470   EXPECT_CALL(*controller->procfs(), ClearFile("/root/trace"))
471       .WillOnce(Return(true));
472   EXPECT_CALL(*controller->procfs(),
473               ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")))
474       .WillRepeatedly(Return(true));
475   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
476   controller.reset();
477   data_source.reset();
478 }
479 
TEST(FtraceControllerTest,BufferSize)480 TEST(FtraceControllerTest, BufferSize) {
481   auto controller = CreateTestController(false /* nice procfs */);
482 
483   // For this test we don't care about most calls to WriteToFile/ClearFile.
484   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
485   EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber());
486 
487   // Every time a fake data source is destroyed, the controller will reset the
488   // buffer size to a single page.
489   EXPECT_CALL(*controller->procfs(),
490               WriteToFile("/root/buffer_size_kb", PageSizeKb()))
491       .Times(AnyNumber());
492 
493   {
494     // No buffer size -> good default (exact value depends on the ram size of
495     // the machine running this test).
496     EXPECT_CALL(
497         *controller->procfs(),
498         WriteToFile("/root/buffer_size_kb", testing::AnyOf("2048", "8192")));
499     FtraceConfig config = CreateFtraceConfig({"group/foo"});
500     auto data_source = controller->AddFakeDataSource(config);
501     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
502   }
503 
504   {
505     // Way too big buffer size -> max size.
506     EXPECT_CALL(*controller->procfs(),
507                 WriteToFile("/root/buffer_size_kb", "65536"));
508     FtraceConfig config = CreateFtraceConfig({"group/foo"});
509     config.set_buffer_size_kb(10 * 1024 * 1024);
510     auto data_source = controller->AddFakeDataSource(config);
511     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
512   }
513 
514   {
515     // The limit is 64mb, 65mb is too much.
516     EXPECT_CALL(*controller->procfs(),
517                 WriteToFile("/root/buffer_size_kb", "65536"));
518     FtraceConfig config = CreateFtraceConfig({"group/foo"});
519     ON_CALL(*controller->procfs(), NumberOfCpus()).WillByDefault(Return(2));
520     config.set_buffer_size_kb(65 * 1024);
521     auto data_source = controller->AddFakeDataSource(config);
522     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
523   }
524 
525   {
526     // Your size ends up with less than 1 page per cpu -> 1 page (gmock already
527     // covered by the cleanup expectation above).
528     FtraceConfig config = CreateFtraceConfig({"group/foo"});
529     config.set_buffer_size_kb(1);
530     auto data_source = controller->AddFakeDataSource(config);
531     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
532   }
533 
534   {
535     // You picked a good size -> your size rounded to nearest page.
536     EXPECT_CALL(*controller->procfs(),
537                 WriteToFile("/root/buffer_size_kb", "64"));
538     FtraceConfig config = CreateFtraceConfig({"group/foo"});
539     config.set_buffer_size_kb(65);
540     auto data_source = controller->AddFakeDataSource(config);
541     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
542   }
543 
544   {
545     // You picked a good size -> your size rounded to nearest page.
546     EXPECT_CALL(*controller->procfs(),
547                 WriteToFile("/root/buffer_size_kb", "64"));
548     FtraceConfig config = CreateFtraceConfig({"group/foo"});
549     ON_CALL(*controller->procfs(), NumberOfCpus()).WillByDefault(Return(2));
550     config.set_buffer_size_kb(65);
551     auto data_source = controller->AddFakeDataSource(config);
552     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
553   }
554 
555   {
556     // buffer_size_lower_bound -> default size no less than given.
557     EXPECT_CALL(
558         *controller->procfs(),
559         WriteToFile("/root/buffer_size_kb", testing::AnyOf("4096", "8192")));
560     FtraceConfig config = CreateFtraceConfig({"group/foo"});
561     config.set_buffer_size_kb(4096);
562     config.set_buffer_size_lower_bound(true);
563     auto data_source = controller->AddFakeDataSource(config);
564     ASSERT_TRUE(controller->StartDataSource(data_source.get()));
565   }
566 }
567 
TEST(FtraceControllerTest,PeriodicDrainConfig)568 TEST(FtraceControllerTest, PeriodicDrainConfig) {
569   auto controller = CreateTestController(false /* nice procfs */);
570 
571   // For this test we don't care about calls to WriteToFile/ClearFile.
572   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
573   EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(AnyNumber());
574 
575   {
576     // No period -> good default.
577     FtraceConfig config = CreateFtraceConfig({"group/foo"});
578     auto data_source = controller->AddFakeDataSource(config);
579     controller->StartDataSource(data_source.get());
580     EXPECT_EQ(100u, controller->tick_period_ms());
581   }
582 
583   {
584     // Pick a tiny value -> good default.
585     FtraceConfig config = CreateFtraceConfig({"group/foo"});
586     config.set_drain_period_ms(0);
587     auto data_source = controller->AddFakeDataSource(config);
588     controller->StartDataSource(data_source.get());
589     EXPECT_EQ(100u, controller->tick_period_ms());
590   }
591 
592   {
593     // Pick a huge value -> good default.
594     FtraceConfig config = CreateFtraceConfig({"group/foo"});
595     config.set_drain_period_ms(1000 * 60 * 60);
596     auto data_source = controller->AddFakeDataSource(config);
597     controller->StartDataSource(data_source.get());
598     EXPECT_EQ(100u, controller->tick_period_ms());
599   }
600 
601   {
602     // Pick a resonable value -> get that value.
603     FtraceConfig config = CreateFtraceConfig({"group/foo"});
604     config.set_drain_period_ms(200);
605     auto data_source = controller->AddFakeDataSource(config);
606     controller->StartDataSource(data_source.get());
607     EXPECT_EQ(200u, controller->tick_period_ms());
608   }
609 }
610 
TEST(FtraceMetadataTest,Clear)611 TEST(FtraceMetadataTest, Clear) {
612   FtraceMetadata metadata;
613   metadata.inode_and_device.insert(std::make_pair(1, 1));
614   metadata.pids.insert(2);
615   metadata.last_seen_device_id = 100;
616   metadata.Clear();
617   EXPECT_THAT(metadata.inode_and_device, IsEmpty());
618   EXPECT_THAT(metadata.pids, IsEmpty());
619   EXPECT_EQ(BlockDeviceID(0), metadata.last_seen_device_id);
620 }
621 
TEST(FtraceMetadataTest,AddDevice)622 TEST(FtraceMetadataTest, AddDevice) {
623   FtraceMetadata metadata;
624   metadata.AddDevice(1);
625   EXPECT_EQ(BlockDeviceID(1), metadata.last_seen_device_id);
626   metadata.AddDevice(3);
627   EXPECT_EQ(BlockDeviceID(3), metadata.last_seen_device_id);
628 }
629 
TEST(FtraceMetadataTest,AddInode)630 TEST(FtraceMetadataTest, AddInode) {
631   FtraceMetadata metadata;
632   metadata.AddCommonPid(getpid() + 1);
633   metadata.AddDevice(3);
634   metadata.AddInode(2);
635   metadata.AddInode(1);
636   metadata.AddCommonPid(getpid() + 1);
637   metadata.AddDevice(4);
638   metadata.AddInode(3);
639 
640   // Check activity from ourselves is excluded.
641   metadata.AddCommonPid(getpid());
642   metadata.AddDevice(5);
643   metadata.AddInode(5);
644 
645   EXPECT_THAT(metadata.inode_and_device,
646               UnorderedElementsAre(Pair(2, 3), Pair(1, 3), Pair(3, 4)));
647 }
648 
TEST(FtraceMetadataTest,AddPid)649 TEST(FtraceMetadataTest, AddPid) {
650   FtraceMetadata metadata;
651   metadata.AddPid(1);
652   metadata.AddPid(2);
653   metadata.AddPid(2);
654   metadata.AddPid(3);
655   EXPECT_THAT(metadata.pids, ElementsAre(1, 2, 3));
656 }
657 
TEST(FtraceStatsTest,Write)658 TEST(FtraceStatsTest, Write) {
659   FtraceStats stats{};
660   FtraceCpuStats cpu_stats{};
661   cpu_stats.cpu = 0;
662   cpu_stats.entries = 1;
663   cpu_stats.overrun = 2;
664   stats.cpu_stats.push_back(cpu_stats);
665 
666   std::unique_ptr<TraceWriterForTesting> writer =
667       std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
668   {
669     auto packet = writer->NewTracePacket();
670     auto* out = packet->set_ftrace_stats();
671     stats.Write(out);
672   }
673 
674   protos::gen::TracePacket result_packet = writer->GetOnlyTracePacket();
675   auto result = result_packet.ftrace_stats().cpu_stats()[0];
676   EXPECT_EQ(result.cpu(), 0u);
677   EXPECT_EQ(result.entries(), 1u);
678   EXPECT_EQ(result.overrun(), 2u);
679 }
680 
TEST(FtraceControllerTest,OnlySecondaryInstance)681 TEST(FtraceControllerTest, OnlySecondaryInstance) {
682   auto controller = CreateTestController(true /* nice procfs */);
683 
684   FtraceConfig config = CreateFtraceConfig({"group/foo"});
685   config.set_instance_name("secondary");
686 
687   // Primary instance won't be touched throughout the entire test.
688   // Exception: allow testing for kernel support of buffer_percent.
689   EXPECT_CALL(*controller->procfs(), ClearFile(_)).Times(0);
690   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(0);
691   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
692       .Times(AnyNumber())
693       .WillRepeatedly(Return(true));
694 
695   // AddDataSource will initialise the tracefs instance, enable the event
696   // through the muxer, but not yet enable tracing_on.
697   auto secondary_procfs = std::unique_ptr<MockFtraceProcfs>(
698       new NiceMock<MockFtraceProcfs>("/root/instances/secondary/", 1));
699   EXPECT_CALL(*secondary_procfs, WriteToFile(_, _)).Times(AnyNumber());
700   EXPECT_CALL(*secondary_procfs,
701               WriteToFile("/root/instances/secondary/tracing_on", "0"));
702   EXPECT_CALL(
703       *secondary_procfs,
704       WriteToFile("/root/instances/secondary/events/group/foo/enable", "1"));
705   controller->PrepareMockProcfsForInstance("secondary",
706                                            std::move(secondary_procfs));
707 
708   // No read tasks posted as part of adding the data source.
709   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
710 
711   std::unique_ptr<FtraceDataSource> data_source =
712       controller->AddFakeDataSource(config);
713   ASSERT_NE(nullptr, data_source);
714 
715   Mock::VerifyAndClearExpectations(
716       controller->GetInstanceMockProcfs("secondary"));
717   Mock::VerifyAndClearExpectations(controller->runner());
718 
719   // StartDataSource will simply enable the event and post a ReadTick.
720   EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
721               WriteToFile("/root/instances/secondary/tracing_on", "1"));
722   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(1);
723 
724   ASSERT_TRUE(controller->StartDataSource(data_source.get()));
725 
726   Mock::VerifyAndClearExpectations(
727       controller->GetInstanceMockProcfs("secondary"));
728   Mock::VerifyAndClearExpectations(controller->runner());
729 
730   // RemoveDataSource will reset the tracefs instance.
731   EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
732               WriteToFile(_, _))
733       .Times(AnyNumber());
734   EXPECT_CALL(
735       *controller->GetInstanceMockProcfs("secondary"),
736       WriteToFile("/root/instances/secondary/events/group/foo/enable", "0"));
737   EXPECT_CALL(
738       *controller->GetInstanceMockProcfs("secondary"),
739       WriteToFile("/root/instances/secondary/buffer_size_kb", PageSizeKb()));
740 
741   controller->RemoveDataSource(data_source.get());
742 
743   // Controller forgot about the instance.
744   EXPECT_FALSE(controller->InstanceExists("secondary"));
745 }
746 
TEST(FtraceControllerTest,DefaultAndSecondaryInstance)747 TEST(FtraceControllerTest, DefaultAndSecondaryInstance) {
748   auto controller = CreateTestController(true /* nice procfs */);
749 
750   FtraceConfig primary_cfg = CreateFtraceConfig({"group/foo"});
751   FtraceConfig secondary_cfg = CreateFtraceConfig({"group/bar"});
752   secondary_cfg.set_instance_name("secondary");
753 
754   // AddDataSource will initialise the tracefs instances, enable the events
755   // through the muxers, but not yet enable tracing_on.
756   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
757   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "0"));
758   EXPECT_CALL(*controller->procfs(),
759               WriteToFile("/root/events/group/foo/enable", "1"));
760 
761   auto secondary_procfs = std::unique_ptr<MockFtraceProcfs>(
762       new NiceMock<MockFtraceProcfs>("/root/instances/secondary/", 1));
763   EXPECT_CALL(*secondary_procfs, WriteToFile(_, _)).Times(AnyNumber());
764   EXPECT_CALL(*secondary_procfs,
765               WriteToFile("/root/instances/secondary/tracing_on", "0"));
766   EXPECT_CALL(
767       *secondary_procfs,
768       WriteToFile("/root/instances/secondary/events/group/bar/enable", "1"));
769   controller->PrepareMockProcfsForInstance("secondary",
770                                            std::move(secondary_procfs));
771 
772   // No read tasks posted as part of adding the data sources.
773   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(0);
774 
775   std::unique_ptr<FtraceDataSource> primary_ds =
776       controller->AddFakeDataSource(primary_cfg);
777   std::unique_ptr<FtraceDataSource> secondary_ds =
778       controller->AddFakeDataSource(secondary_cfg);
779   ASSERT_NE(nullptr, primary_ds);
780   ASSERT_NE(nullptr, secondary_ds);
781   ASSERT_NE(primary_ds->config_id(), secondary_ds->config_id());
782 
783   Mock::VerifyAndClearExpectations(controller->procfs());
784   Mock::VerifyAndClearExpectations(
785       controller->GetInstanceMockProcfs("secondary"));
786   Mock::VerifyAndClearExpectations(controller->runner());
787 
788   // StartDataSource will simply enable the events and post two ReadTicks (one
789   // per instance having the first data source activated), with the first tick
790   // becoming obsolete.
791   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/tracing_on", "1"));
792   EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
793               WriteToFile("/root/instances/secondary/tracing_on", "1"));
794   EXPECT_CALL(*controller->procfs(), WriteToFile("/root/buffer_percent", _))
795       .WillRepeatedly(Return(true));
796   EXPECT_CALL(*controller->runner(), PostDelayedTask(_, _)).Times(2);
797 
798   ASSERT_TRUE(controller->StartDataSource(primary_ds.get()));
799   ASSERT_TRUE(controller->StartDataSource(secondary_ds.get()));
800 
801   Mock::VerifyAndClearExpectations(controller->procfs());
802   Mock::VerifyAndClearExpectations(
803       controller->GetInstanceMockProcfs("secondary"));
804   Mock::VerifyAndClearExpectations(controller->runner());
805 
806   // RemoveDataSource will reset the tracefs instances.
807   EXPECT_CALL(*controller->procfs(), WriteToFile(_, _)).Times(AnyNumber());
808   EXPECT_CALL(*controller->procfs(),
809               WriteToFile("/root/events/group/foo/enable", "0"));
810 
811   EXPECT_CALL(*controller->GetInstanceMockProcfs("secondary"),
812               WriteToFile(_, _))
813       .Times(AnyNumber());
814   EXPECT_CALL(
815       *controller->GetInstanceMockProcfs("secondary"),
816       WriteToFile("/root/instances/secondary/events/group/bar/enable", "0"));
817 
818   controller->RemoveDataSource(primary_ds.get());
819   controller->RemoveDataSource(secondary_ds.get());
820 
821   // Controller forgot about the secondary instance.
822   EXPECT_FALSE(controller->InstanceExists("secondary"));
823 }
824 
TEST(FtraceControllerTest,TracefsInstanceFilepaths)825 TEST(FtraceControllerTest, TracefsInstanceFilepaths) {
826   std::optional<std::string> path;
827   path = FtraceController::AbsolutePathForInstance("/root/", "test");
828   EXPECT_EQ(*path, "/root/instances/test/");
829 
830   // named directory should stay under instances/
831   path = FtraceController::AbsolutePathForInstance("/root/", "test/test");
832   EXPECT_FALSE(path.has_value());
833   path = FtraceController::AbsolutePathForInstance("/root/", "..");
834   EXPECT_FALSE(path.has_value());
835 
836   // special-cased pkvm path
837   path = FtraceController::AbsolutePathForInstance("/root/", "hyp");
838   EXPECT_EQ(*path, "/root/hyp/");
839 }
840 
TEST(FtraceControllerTest,PollSupportedOnKernelVersion)841 TEST(FtraceControllerTest, PollSupportedOnKernelVersion) {
842   auto test = [](auto s) {
843     return FtraceController::PollSupportedOnKernelVersion(s);
844   };
845   // Linux 6.1 or above are ok
846   EXPECT_TRUE(test("6.5.13-1-amd64"));
847   EXPECT_TRUE(test("6.1.0-1-amd64"));
848   EXPECT_TRUE(test("6.1.25-android14-11-g"));
849   // before 6.1
850   EXPECT_FALSE(test("5.15.200-1-amd"));
851 
852   // Android: check allowlisted GKI versions
853 
854   // sublevel matters:
855   EXPECT_TRUE(test("5.10.198-android13-4-0"));
856   EXPECT_FALSE(test("5.10.189-android13-4-0"));
857   // sublevel matters:
858   EXPECT_TRUE(test("5.15.137-android14-8-suffix"));
859   EXPECT_FALSE(test("5.15.130-android14-8-suffix"));
860   // sublevel matters:
861   EXPECT_TRUE(test("5.15.137-android13-8-0"));
862   EXPECT_FALSE(test("5.15.129-android13-8-0"));
863   // android12 instead of android13 (clarification: this is part of the kernel
864   // version, and is unrelated to the system image version).
865   EXPECT_FALSE(test("5.10.198-android12-4-0"));
866 }
867 
868 }  // namespace perfetto
869