Home | History | Annotate | Download | only in logd
      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 
     25 Prune::Prune(uid_t uid, pid_t pid)
     26         : mUid(uid)
     27         , mPid(pid)
     28 { }
     29 
     30 int 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 
     40 void 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 
     49 PruneList::PruneList()
     50         : mWorstUidEnabled(false) {
     51     mNaughty.clear();
     52     mNice.clear();
     53 }
     54 
     55 PruneList::~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 
     67 int 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 
    174 void 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 
    221 bool 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 
    231 bool 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