1 /*
2 * Copyright (C) 2014 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 "PruneList.h"
18
19 #include <ctype.h>
20
21 #include <android-base/logging.h>
22 #include <android-base/properties.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25
Matches(LogBufferElement * element) const26 bool Prune::Matches(LogBufferElement* element) const {
27 return (uid_ == UID_ALL || uid_ == element->uid()) &&
28 (pid_ == PID_ALL || pid_ == element->pid());
29 }
30
Format() const31 std::string Prune::Format() const {
32 if (uid_ != UID_ALL) {
33 if (pid_ != PID_ALL) {
34 return android::base::StringPrintf("%u/%u", uid_, pid_);
35 }
36 return android::base::StringPrintf("%u", uid_);
37 }
38 if (pid_ != PID_ALL) {
39 return android::base::StringPrintf("/%u", pid_);
40 }
41 // NB: pid_ == PID_ALL can not happen if uid_ == UID_ALL
42 return std::string("/");
43 }
44
PruneList()45 PruneList::PruneList() {
46 Init(nullptr);
47 }
48
Init(const char * str)49 bool PruneList::Init(const char* str) {
50 high_priority_prune_.clear();
51 low_priority_prune_.clear();
52
53 // default here means take ro.logd.filter, persist.logd.filter then internal default in order.
54 if (str && !strcmp(str, "default")) {
55 str = nullptr;
56 }
57 if (str && !strcmp(str, "disable")) {
58 str = "";
59 }
60
61 std::string filter;
62
63 if (str) {
64 filter = str;
65 } else {
66 filter = android::base::GetProperty("ro.logd.filter", "default");
67 auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
68 // default here means take ro.logd.filter
69 if (persist_filter != "default") {
70 filter = persist_filter;
71 }
72 }
73
74 // default here means take internal default.
75 if (filter == "default") {
76 filter = "~! ~1000/!";
77 }
78 if (filter == "disable") {
79 filter = "";
80 }
81
82 worst_uid_enabled_ = false;
83 worst_pid_of_system_enabled_ = false;
84
85 for (str = filter.c_str(); *str; ++str) {
86 if (isspace(*str)) {
87 continue;
88 }
89
90 std::list<Prune>* list;
91 if (*str == '~' || *str == '!') { // ~ supported, ! undocumented
92 ++str;
93 // special case, prune the worst UID of those using at least 1/8th of the buffer.
94 if (*str == '!') {
95 worst_uid_enabled_ = true;
96 ++str;
97 if (!*str) {
98 break;
99 }
100 if (!isspace(*str)) {
101 LOG(ERROR) << "Nothing expected after '~!', but found '" << str << "'";
102 return false;
103 }
104 continue;
105 }
106 // special case, translated to worst PID of System at priority
107 static const char WORST_SYSTEM_PID[] = "1000/!";
108 if (!strncmp(str, WORST_SYSTEM_PID, sizeof(WORST_SYSTEM_PID) - 1)) {
109 worst_pid_of_system_enabled_ = true;
110 str += sizeof(WORST_SYSTEM_PID) - 1;
111 if (!*str) {
112 break;
113 }
114 if (!isspace(*str)) {
115 LOG(ERROR) << "Nothing expected after '~1000/!', but found '" << str << "'";
116 return false;
117 }
118 continue;
119 }
120 if (!*str) {
121 LOG(ERROR) << "Expected UID or PID after '~', but found nothing";
122 return false;
123 }
124 list = &high_priority_prune_;
125 } else {
126 list = &low_priority_prune_;
127 }
128
129 uid_t uid = Prune::UID_ALL;
130 if (isdigit(*str)) {
131 uid = 0;
132 do {
133 uid = uid * 10 + *str++ - '0';
134 } while (isdigit(*str));
135 }
136
137 pid_t pid = Prune::PID_ALL;
138 if (*str == '/') {
139 ++str;
140 if (isdigit(*str)) {
141 pid = 0;
142 do {
143 pid = pid * 10 + *str++ - '0';
144 } while (isdigit(*str));
145 }
146 }
147
148 if (uid == Prune::UID_ALL && pid == Prune::PID_ALL) {
149 LOG(ERROR) << "Expected UID/PID combination, but found none";
150 return false;
151 }
152
153 if (*str && !isspace(*str)) {
154 LOG(ERROR) << "Nothing expected after UID/PID combination, but found '" << str << "'";
155 return false;
156 }
157
158 list->emplace_back(uid, pid);
159 if (!*str) {
160 break;
161 }
162 }
163
164 return true;
165 }
166
Format() const167 std::string PruneList::Format() const {
168 std::vector<std::string> prune_rules;
169
170 if (worst_uid_enabled_) {
171 prune_rules.emplace_back("~!");
172 }
173 if (worst_pid_of_system_enabled_) {
174 prune_rules.emplace_back("~1000/!");
175 }
176 for (const auto& rule : low_priority_prune_) {
177 prune_rules.emplace_back(rule.Format());
178 }
179 for (const auto& rule : high_priority_prune_) {
180 prune_rules.emplace_back("~" + rule.Format());
181 }
182 return android::base::Join(prune_rules, " ");
183 }
184
IsHighPriority(LogBufferElement * element) const185 bool PruneList::IsHighPriority(LogBufferElement* element) const {
186 for (const auto& rule : high_priority_prune_) {
187 if (rule.Matches(element)) {
188 return true;
189 }
190 }
191 return false;
192 }
193
IsLowPriority(LogBufferElement * element) const194 bool PruneList::IsLowPriority(LogBufferElement* element) const {
195 for (const auto& rule : low_priority_prune_) {
196 if (rule.Matches(element)) {
197 return true;
198 }
199 }
200 return false;
201 }
202