blob: 9728db17bd69baa9642d945dd8d77b166fc244b5 [file] [log] [blame]
Mark Salyzyndfa7a072014-02-11 12:29:31 -08001/*
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
Mark Salyzyndfa7a072014-02-11 12:29:31 -080017#include <ctype.h>
18
19#include <utils/String8.h>
20
21#include "LogWhiteBlackList.h"
22
23// White and Black list
24
25Prune::Prune(uid_t uid, pid_t pid)
26 : mUid(uid)
27 , mPid(pid)
28{ }
29
30int Prune::cmp(uid_t uid, pid_t pid) const {
31 if ((mUid == uid_all) || (mUid == uid)) {
32 if (mPid == pid_all) {
33 return 0;
34 }
35 return pid - mPid;
36 }
37 return uid - mUid;
38}
39
40void Prune::format(char **strp) {
41 if (mUid != uid_all) {
Chih-Hung Hsieh634118e2014-09-12 16:02:28 -070042 if (mPid != pid_all) {
43 asprintf(strp, "%u/%u", mUid, mPid);
44 } else {
45 asprintf(strp, "%u", mUid);
46 }
47 } else if (mPid != pid_all) {
48 asprintf(strp, "/%u", mPid);
49 } else { // NB: mPid == pid_all can not happen if mUid == uid_all
50 asprintf(strp, "/");
Mark Salyzyndfa7a072014-02-11 12:29:31 -080051 }
52}
53
54PruneList::PruneList()
Mark Salyzyn4141cb22014-05-06 13:49:28 -070055 : mWorstUidEnabled(false) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -080056 mNaughty.clear();
57 mNice.clear();
58}
59
60PruneList::~PruneList() {
61 PruneCollection::iterator it;
62 for (it = mNice.begin(); it != mNice.end();) {
63 delete (*it);
64 it = mNice.erase(it);
65 }
66 for (it = mNaughty.begin(); it != mNaughty.end();) {
67 delete (*it);
68 it = mNaughty.erase(it);
69 }
70}
71
72int PruneList::init(char *str) {
Mark Salyzyn4141cb22014-05-06 13:49:28 -070073 mWorstUidEnabled = false;
Mark Salyzyndfa7a072014-02-11 12:29:31 -080074 PruneCollection::iterator it;
75 for (it = mNice.begin(); it != mNice.end();) {
76 delete (*it);
77 it = mNice.erase(it);
78 }
79 for (it = mNaughty.begin(); it != mNaughty.end();) {
80 delete (*it);
81 it = mNaughty.erase(it);
82 }
83
84 if (!str) {
85 return 0;
86 }
87
88 mWorstUidEnabled = false;
89
90 for(; *str; ++str) {
91 if (isspace(*str)) {
92 continue;
93 }
94
95 PruneCollection *list;
96 if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
97 ++str;
98 // special case, translates to worst UID at priority in blacklist
99 if (*str == '!') {
100 mWorstUidEnabled = true;
101 ++str;
102 if (!*str) {
103 break;
104 }
105 if (!isspace(*str)) {
106 return 1;
107 }
108 continue;
109 }
110 if (!*str) {
111 return 1;
112 }
113 list = &mNaughty;
114 } else {
115 list = &mNice;
116 }
117
118 uid_t uid = Prune::uid_all;
119 if (isdigit(*str)) {
120 uid = 0;
121 do {
122 uid = uid * 10 + *str++ - '0';
123 } while (isdigit(*str));
124 }
125
126 pid_t pid = Prune::pid_all;
127 if (*str == '/') {
128 ++str;
129 if (isdigit(*str)) {
130 pid = 0;
131 do {
132 pid = pid * 10 + *str++ - '0';
133 } while (isdigit(*str));
134 }
135 }
136
137 if ((uid == Prune::uid_all) && (pid == Prune::pid_all)) {
138 return 1;
139 }
140
141 if (*str && !isspace(*str)) {
142 return 1;
143 }
144
145 // insert sequentially into list
146 PruneCollection::iterator it = list->begin();
147 while (it != list->end()) {
148 Prune *p = *it;
149 int m = uid - p->mUid;
150 if (m == 0) {
151 if (p->mPid == p->pid_all) {
152 break;
153 }
154 if ((pid == p->pid_all) && (p->mPid != p->pid_all)) {
155 it = list->erase(it);
156 continue;
157 }
158 m = pid - p->mPid;
159 }
Mark Salyzyn22e287d2014-03-21 13:12:16 -0700160 if (m <= 0) {
161 if (m < 0) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800162 list->insert(it, new Prune(uid,pid));
163 }
164 break;
165 }
166 ++it;
167 }
168 if (it == list->end()) {
169 list->push_back(new Prune(uid,pid));
170 }
171 if (!*str) {
172 break;
173 }
174 }
175
176 return 0;
177}
178
179void PruneList::format(char **strp) {
180 if (*strp) {
181 free(*strp);
182 *strp = NULL;
183 }
184
185 static const char nice_format[] = " %s";
186 const char *fmt = nice_format + 1;
187
188 android::String8 string;
189
190 if (mWorstUidEnabled) {
191 string.setTo("~!");
192 fmt = nice_format;
193 }
194
195 PruneCollection::iterator it;
196
197 for (it = mNice.begin(); it != mNice.end(); ++it) {
198 char *a = NULL;
199 (*it)->format(&a);
200
201 string.appendFormat(fmt, a);
202 fmt = nice_format;
203
204 free(a);
205 }
206
207 static const char naughty_format[] = " ~%s";
208 fmt = naughty_format + (*fmt != ' ');
209 for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
210 char *a = NULL;
211 (*it)->format(&a);
212
213 string.appendFormat(fmt, a);
214 fmt = naughty_format;
215
216 free(a);
217 }
218
219 *strp = strdup(string.string());
220}
221
222// ToDo: Lists are in sorted order, Prune->cmp() returns + or -
223// If there is scaling issues, resort to a better algorithm than linear
224// based on these assumptions.
225
226bool PruneList::naughty(LogBufferElement *element) {
227 PruneCollection::iterator it;
228 for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
229 if (!(*it)->cmp(element)) {
230 return true;
231 }
232 }
233 return false;
234}
235
236bool PruneList::nice(LogBufferElement *element) {
237 PruneCollection::iterator it;
238 for (it = mNice.begin(); it != mNice.end(); ++it) {
239 if (!(*it)->cmp(element)) {
240 return true;
241 }
242 }
243 return false;
244}