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