Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2012 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 "shill/scope_logger.h"
     18 
     19 #include <vector>
     20 
     21 #include <base/strings/string_tokenizer.h>
     22 #include <base/strings/string_util.h>
     23 
     24 using base::StringTokenizer;
     25 using std::string;
     26 using std::vector;
     27 
     28 namespace shill {
     29 
     30 namespace {
     31 
     32 const int kDefaultVerboseLevel = 0;
     33 
     34 // Scope names corresponding to the scope defined by ScopeLogger::Scope.
     35 const char* const kScopeNames[] = {
     36   "binder",
     37   "cellular",
     38   "connection",
     39   "crypto",
     40   "daemon",
     41   "dbus",
     42   "device",
     43   "dhcp",
     44   "dns",
     45   "ethernet",
     46   "http",
     47   "httpproxy",
     48   "inet",
     49   "link",
     50   "manager",
     51   "metrics",
     52   "modem",
     53   "portal",
     54   "power",
     55   "ppp",
     56   "pppoe",
     57   "profile",
     58   "property",
     59   "resolver",
     60   "route",
     61   "rtnl",
     62   "service",
     63   "storage",
     64   "task",
     65   "vpn",
     66   "wifi",
     67   "wimax",
     68 };
     69 
     70 static_assert(arraysize(kScopeNames) == ScopeLogger::kNumScopes,
     71               "Scope tags do not have expected number of strings");
     72 
     73 // ScopeLogger needs to be a 'leaky' singleton as it needs to survive to
     74 // handle logging till the very end of the shill process. Making ScopeLogger
     75 // leaky is fine as it does not need to clean up or release any resource at
     76 // destruction.
     77 base::LazyInstance<ScopeLogger>::Leaky g_scope_logger =
     78     LAZY_INSTANCE_INITIALIZER;
     79 
     80 }  // namespace
     81 
     82 // static
     83 ScopeLogger* ScopeLogger::GetInstance() {
     84   return g_scope_logger.Pointer();
     85 }
     86 
     87 ScopeLogger::ScopeLogger()
     88     : verbose_level_(kDefaultVerboseLevel) {
     89 }
     90 
     91 ScopeLogger::~ScopeLogger() {
     92 }
     93 
     94 bool ScopeLogger::IsLogEnabled(Scope scope, int verbose_level) const {
     95   return IsScopeEnabled(scope) && verbose_level <= verbose_level_;
     96 }
     97 
     98 bool ScopeLogger::IsScopeEnabled(Scope scope) const {
     99   CHECK_GE(scope, 0);
    100   CHECK_LT(scope, kNumScopes);
    101 
    102   return scope_enabled_[scope];
    103 }
    104 
    105 string ScopeLogger::GetAllScopeNames() const {
    106   vector<string> names(kScopeNames, kScopeNames + arraysize(kScopeNames));
    107   return base::JoinString(names, "+");
    108 }
    109 
    110 string ScopeLogger::GetEnabledScopeNames() const {
    111   vector<string> names;
    112   for (size_t i = 0; i < arraysize(kScopeNames); ++i) {
    113     if (scope_enabled_[i])
    114       names.push_back(kScopeNames[i]);
    115   }
    116   return base::JoinString(names, "+");
    117 }
    118 
    119 void ScopeLogger::EnableScopesByName(const string& expression) {
    120   if (expression.empty()) {
    121     DisableAllScopes();
    122     return;
    123   }
    124 
    125   // As described in the header file, if the first scope name in the
    126   // sequence specified by |expression| is not prefixed by a plus or
    127   // minus sign, it indicates that all scopes are first disabled before
    128   // enabled by |expression|.
    129   if (expression[0] != '+' && expression[0] != '-')
    130     DisableAllScopes();
    131 
    132   bool enable_scope = true;
    133   StringTokenizer tokenizer(expression, "+-");
    134   tokenizer.set_options(StringTokenizer::RETURN_DELIMS);
    135   while (tokenizer.GetNext()) {
    136     if (tokenizer.token_is_delim()) {
    137       enable_scope = (tokenizer.token() == "+");
    138       continue;
    139     }
    140 
    141     if (tokenizer.token().empty())
    142       continue;
    143 
    144     size_t i;
    145     for (i = 0; i < arraysize(kScopeNames); ++i) {
    146       if (tokenizer.token() == kScopeNames[i]) {
    147         SetScopeEnabled(static_cast<Scope>(i), enable_scope);
    148         break;
    149       }
    150     }
    151     LOG_IF(WARNING, i == arraysize(kScopeNames))
    152         << "Unknown scope '" << tokenizer.token() << "'";
    153   }
    154 }
    155 
    156 void ScopeLogger::RegisterScopeEnableChangedCallback(
    157     Scope scope, ScopeEnableChangedCallback callback) {
    158   CHECK_GE(scope, 0);
    159   CHECK_LT(scope, kNumScopes);
    160   log_scope_callbacks_[scope].push_back(callback);
    161 }
    162 
    163 void ScopeLogger::DisableAllScopes() {
    164   // Iterate over all scopes so the notification side-effect occurs.
    165   for (size_t i = 0; i < arraysize(kScopeNames); ++i) {
    166     SetScopeEnabled(static_cast<Scope>(i), false);
    167   }
    168 }
    169 
    170 void ScopeLogger::SetScopeEnabled(Scope scope, bool enabled) {
    171   CHECK_GE(scope, 0);
    172   CHECK_LT(scope, kNumScopes);
    173 
    174   if (scope_enabled_[scope] != enabled) {
    175     for (const auto& callback : log_scope_callbacks_[scope]) {
    176       callback.Run(enabled);
    177     }
    178   }
    179 
    180   scope_enabled_[scope] = enabled;
    181 }
    182 
    183 }  // namespace shill
    184