1 /*
2  * Copyright (C) 2021 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 #pragma once
18 
19 #include <sys/types.h>
20 
21 #include <optional>
22 #include <regex>
23 #include <set>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27 
28 #include "command.h"
29 #include "record.h"
30 #include "thread_tree.h"
31 
32 namespace simpleperf {
33 
34 #define RECORD_FILTER_OPTION_HELP_MSG                                                              \
35   "--exclude-pid pid1,pid2,...   Exclude samples for selected processes.\n"                        \
36   "--exclude-tid tid1,tid2,...   Exclude samples for selected threads.\n"                          \
37   "--exclude-process-name process_name_regex   Exclude samples for processes with name\n"          \
38   "                                            containing the regular expression.\n"               \
39   "--exclude-thread-name thread_name_regex     Exclude samples for threads with name containing\n" \
40   "                                            the regular expression.\n"                          \
41   "--exclude-uid uid1,uid2,...   Exclude samples for processes belonging to selected uids.\n"      \
42   "--include-pid pid1,pid2,...   Include samples for selected processes.\n"                        \
43   "--include-tid tid1,tid2,...   Include samples for selected threads.\n"                          \
44   "--include-process-name process_name_regex   Include samples for processes with name\n"          \
45   "                                            containing the regular expression.\n"               \
46   "--include-thread-name thread_name_regex     Include samples for threads with name containing\n" \
47   "                                            the regular expression.\n"                          \
48   "--include-uid uid1,uid2,...   Include samples for processes belonging to selected uids.\n"
49 
50 struct RecordFilterCondition {
51   bool used = false;
52   std::set<pid_t> pids;
53   std::set<pid_t> tids;
54   std::vector<std::regex> process_name_regs;
55   std::vector<std::regex> thread_name_regs;
56   std::set<uid_t> uids;
57 };
58 
59 // Filter SampleRecords based on the rule below:
60 //   out_sample_records = (in_sample_records & ~exclude_conditions) & include_conditions
61 //   By default, exclude_conditions = 0, include_conditions = 1.
62 class RecordFilter {
63  public:
RecordFilter(const ThreadTree & thread_tree)64   RecordFilter(const ThreadTree& thread_tree) : thread_tree_(thread_tree) {}
65   bool ParseOptions(OptionValueMap& options);
66   void AddPids(const std::set<pid_t>& pids, bool exclude);
67   void AddTids(const std::set<pid_t>& tids, bool exclude);
68   void AddProcessNameRegex(const std::string& process_name, bool exclude);
69   void AddThreadNameRegex(const std::string& thread_name, bool exclude);
70   void AddUids(const std::set<uid_t>& uids, bool exclude);
71 
72   // Return true if the record passes filter.
73   bool Check(const SampleRecord* r);
74 
GetCondition(bool exclude)75   RecordFilterCondition& GetCondition(bool exclude) {
76     return exclude ? exclude_condition_ : include_condition_;
77   }
78   void Clear();
79 
80  private:
81   bool CheckCondition(const SampleRecord* r, const RecordFilterCondition& condition);
82   bool SearchInRegs(const std::string& s, const std::vector<std::regex>& regs);
83   std::optional<uid_t> GetUidForProcess(pid_t pid);
84 
85   const ThreadTree& thread_tree_;
86   RecordFilterCondition exclude_condition_;
87   RecordFilterCondition include_condition_;
88   std::unordered_map<pid_t, std::optional<uid_t>> pid_to_uid_map_;
89 };
90 
GetRecordFilterOptionFormats()91 inline const OptionFormatMap& GetRecordFilterOptionFormats() {
92   static const OptionFormatMap option_formats = {
93       {"--exclude-pid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
94       {"--exclude-tid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
95       {"--exclude-process-name",
96        {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
97       {"--exclude-thread-name",
98        {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
99       {"--exclude-uid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
100       {"--include-pid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
101       {"--include-tid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
102       {"--include-process-name",
103        {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
104       {"--include-thread-name",
105        {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
106       {"--include-uid", {OptionValueType::STRING, OptionType::MULTIPLE, AppRunnerType::ALLOWED}},
107   };
108   return option_formats;
109 }
110 
111 }  // namespace simpleperf
112