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 <android-base/stringprintf.h>
     20 #include <cutils/properties.h>
     21 
     22 #include "LogWhiteBlackList.h"
     23 
     24 // White and Black list
     25 
     26 Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
     27 }
     28 
     29 int Prune::cmp(uid_t uid, pid_t pid) const {
     30     if ((mUid == uid_all) || (mUid == uid)) {
     31         if (mPid == pid_all) {
     32             return 0;
     33         }
     34         return pid - mPid;
     35     }
     36     return uid - mUid;
     37 }
     38 
     39 std::string Prune::format() {
     40     if (mUid != uid_all) {
     41         if (mPid != pid_all) {
     42             return android::base::StringPrintf("%u/%u", mUid, mPid);
     43         }
     44         return android::base::StringPrintf("%u", mUid);
     45     }
     46     if (mPid != pid_all) {
     47         return android::base::StringPrintf("/%u", mPid);
     48     }
     49     // NB: mPid == pid_all can not happen if mUid == uid_all
     50     return std::string("/");
     51 }
     52 
     53 PruneList::PruneList() {
     54     init(NULL);
     55 }
     56 
     57 PruneList::~PruneList() {
     58     PruneCollection::iterator it;
     59     for (it = mNice.begin(); it != mNice.end();) {
     60         it = mNice.erase(it);
     61     }
     62     for (it = mNaughty.begin(); it != mNaughty.end();) {
     63         it = mNaughty.erase(it);
     64     }
     65 }
     66 
     67 int PruneList::init(const char* str) {
     68     mWorstUidEnabled = true;
     69     mWorstPidOfSystemEnabled = true;
     70     PruneCollection::iterator it;
     71     for (it = mNice.begin(); it != mNice.end();) {
     72         it = mNice.erase(it);
     73     }
     74     for (it = mNaughty.begin(); it != mNaughty.end();) {
     75         it = mNaughty.erase(it);
     76     }
     77 
     78     static const char _default[] = "default";
     79     // default here means take ro.logd.filter, persist.logd.filter then
     80     // internal default in that order.
     81     if (str && !strcmp(str, _default)) {
     82         str = NULL;
     83     }
     84     static const char _disable[] = "disable";
     85     if (str && !strcmp(str, _disable)) {
     86         str = "";
     87     }
     88 
     89     std::string filter;
     90 
     91     if (str) {
     92         filter = str;
     93     } else {
     94         char property[PROPERTY_VALUE_MAX];
     95         property_get("ro.logd.filter", property, _default);
     96         filter = property;
     97         property_get("persist.logd.filter", property, filter.c_str());
     98         // default here means take ro.logd.filter
     99         if (strcmp(property, _default)) {
    100             filter = property;
    101         }
    102     }
    103 
    104     // default here means take internal default.
    105     if (filter == _default) {
    106         // See README.property for description of filter format
    107         filter = "~! ~1000/!";
    108     }
    109     if (filter == _disable) {
    110         filter = "";
    111     }
    112 
    113     mWorstUidEnabled = false;
    114     mWorstPidOfSystemEnabled = false;
    115 
    116     for (str = filter.c_str(); *str; ++str) {
    117         if (isspace(*str)) {
    118             continue;
    119         }
    120 
    121         PruneCollection* list;
    122         if ((*str == '~') || (*str == '!')) {  // ~ supported, ! undocumented
    123             ++str;
    124             // special case, translates to worst UID at priority in blacklist
    125             if (*str == '!') {
    126                 mWorstUidEnabled = true;
    127                 ++str;
    128                 if (!*str) {
    129                     break;
    130                 }
    131                 if (!isspace(*str)) {
    132                     return 1;
    133                 }
    134                 continue;
    135             }
    136             // special case, translated to worst PID of System at priority
    137             static const char worstPid[] = "1000/!";
    138             if (!strncmp(str, worstPid, sizeof(worstPid) - 1)) {
    139                 mWorstPidOfSystemEnabled = true;
    140                 str += sizeof(worstPid) - 1;
    141                 if (!*str) {
    142                     break;
    143                 }
    144                 if (!isspace(*str)) {
    145                     return 1;
    146                 }
    147                 continue;
    148             }
    149             if (!*str) {
    150                 return 1;
    151             }
    152             list = &mNaughty;
    153         } else {
    154             list = &mNice;
    155         }
    156 
    157         uid_t uid = Prune::uid_all;
    158         if (isdigit(*str)) {
    159             uid = 0;
    160             do {
    161                 uid = uid * 10 + *str++ - '0';
    162             } while (isdigit(*str));
    163         }
    164 
    165         pid_t pid = Prune::pid_all;
    166         if (*str == '/') {
    167             ++str;
    168             if (isdigit(*str)) {
    169                 pid = 0;
    170                 do {
    171                     pid = pid * 10 + *str++ - '0';
    172                 } while (isdigit(*str));
    173             }
    174         }
    175 
    176         if ((uid == Prune::uid_all) && (pid == Prune::pid_all)) {
    177             return 1;
    178         }
    179 
    180         if (*str && !isspace(*str)) {
    181             return 1;
    182         }
    183 
    184         // insert sequentially into list
    185         PruneCollection::iterator it = list->begin();
    186         while (it != list->end()) {
    187             Prune& p = *it;
    188             int m = uid - p.mUid;
    189             if (m == 0) {
    190                 if (p.mPid == p.pid_all) {
    191                     break;
    192                 }
    193                 if ((pid == p.pid_all) && (p.mPid != p.pid_all)) {
    194                     it = list->erase(it);
    195                     continue;
    196                 }
    197                 m = pid - p.mPid;
    198             }
    199             if (m <= 0) {
    200                 if (m < 0) {
    201                     list->insert(it, Prune(uid, pid));
    202                 }
    203                 break;
    204             }
    205             ++it;
    206         }
    207         if (it == list->end()) {
    208             list->push_back(Prune(uid, pid));
    209         }
    210         if (!*str) {
    211             break;
    212         }
    213     }
    214 
    215     return 0;
    216 }
    217 
    218 std::string PruneList::format() {
    219     static const char nice_format[] = " %s";
    220     const char* fmt = nice_format + 1;
    221 
    222     std::string string;
    223 
    224     if (mWorstUidEnabled) {
    225         string = "~!";
    226         fmt = nice_format;
    227         if (mWorstPidOfSystemEnabled) {
    228             string += " ~1000/!";
    229         }
    230     }
    231 
    232     PruneCollection::iterator it;
    233 
    234     for (it = mNice.begin(); it != mNice.end(); ++it) {
    235         string += android::base::StringPrintf(fmt, (*it).format().c_str());
    236         fmt = nice_format;
    237     }
    238 
    239     static const char naughty_format[] = " ~%s";
    240     fmt = naughty_format + (*fmt != ' ');
    241     for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
    242         string += android::base::StringPrintf(fmt, (*it).format().c_str());
    243         fmt = naughty_format;
    244     }
    245 
    246     return string;
    247 }
    248 
    249 // ToDo: Lists are in sorted order, Prune->cmp() returns + or -
    250 // If there is scaling issues, resort to a better algorithm than linear
    251 // based on these assumptions.
    252 
    253 bool PruneList::naughty(LogBufferElement* element) {
    254     PruneCollection::iterator it;
    255     for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
    256         if (!(*it).cmp(element)) {
    257             return true;
    258         }
    259     }
    260     return false;
    261 }
    262 
    263 bool PruneList::nice(LogBufferElement* element) {
    264     PruneCollection::iterator it;
    265     for (it = mNice.begin(); it != mNice.end(); ++it) {
    266         if (!(*it).cmp(element)) {
    267             return true;
    268         }
    269     }
    270     return false;
    271 }
    272