• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "properties.h"
17 
18 #include <array>
19 #include <atomic>
20 #include <cassert>
21 #include <climits>
22 #include <cstdio>
23 #include <cstring>
24 #include <ctime>
25 #include <fstream>
26 #include <functional>
27 #include <iostream>
28 #include <pthread.h>
29 #include <shared_mutex>
30 #include <sstream>
31 #include <string>
32 #include <strstream>
33 #include <sys/uio.h>
34 #include <unistd.h>
35 #include <unordered_map>
36 
37 #include <hilog/log.h>
38 #include <parameter.h>
39 #include <sysparam_errno.h>
40 
41 using namespace std;
42 
43 using ReadLock = shared_lock<shared_timed_mutex>;
44 using InsertLock = unique_lock<shared_timed_mutex>;
45 
46 static pthread_mutex_t g_globalLevelLock = PTHREAD_MUTEX_INITIALIZER;
47 static pthread_mutex_t g_tagLevelLock = PTHREAD_MUTEX_INITIALIZER;
48 static pthread_mutex_t g_domainLevelLock = PTHREAD_MUTEX_INITIALIZER;
49 static pthread_mutex_t g_debugLock = PTHREAD_MUTEX_INITIALIZER;
50 static pthread_mutex_t g_persistDebugLock = PTHREAD_MUTEX_INITIALIZER;
51 static pthread_mutex_t g_privateLock = PTHREAD_MUTEX_INITIALIZER;
52 static pthread_mutex_t g_processFlowLock = PTHREAD_MUTEX_INITIALIZER;
53 static pthread_mutex_t g_domainFlowLock = PTHREAD_MUTEX_INITIALIZER;
54 static pthread_mutex_t g_kmsgLock = PTHREAD_MUTEX_INITIALIZER;
55 
56 static int LockByProp(uint32_t propType);
57 static void UnlockByProp(uint32_t propType);
58 
59 class PropertyTypeLocker {
60 public:
PropertyTypeLocker(uint32_t propType)61     explicit PropertyTypeLocker(uint32_t propType)
62         : m_propType(propType)
63         , m_isLocked(false)
64     {
65         m_isLocked = !LockByProp(m_propType);
66     }
67 
~PropertyTypeLocker()68     ~PropertyTypeLocker()
69     {
70         if (m_isLocked) {
71             UnlockByProp(m_propType);
72         }
73     }
74 
isLocked() const75     bool isLocked() const
76     {
77         return m_isLocked;
78     }
79 private:
80     uint32_t m_propType;
81     bool m_isLocked;
82 };
83 
84 using RawPropertyData = std::array<char, HILOG_PROP_VALUE_MAX>;
85 
86 template<typename T>
87 class CacheData {
88 public:
89     using DataConverter = std::function<T(const RawPropertyData&, const T& defaultVal)>;
90 
CacheData(DataConverter converter,const T & defaultValue,uint32_t propType,const std::string & suffix="")91     CacheData(DataConverter converter, const T& defaultValue, uint32_t propType, const std::string& suffix = "")
92         : m_value(defaultValue)
93         , m_defaultValue(defaultValue)
94         , m_propType(propType)
95         , m_converter(converter)
96     {
97         m_key = GetPropertyName(m_propType) + suffix;
98     }
99 
getValue()100     T getValue()
101     {
102         if (m_handle == -1) {
103             if (m_commit == 0) { // temparary solution, after sysparam supply get_global_commitid, FIXME
104                 return m_defaultValue;
105             }
106             auto handle = FindParameter(m_key.c_str());
107             if (handle == -1) {
108                 m_commit = 0; // temparary solution, after sysparam supply get_global_commitid, FIXME
109                 return m_defaultValue;
110             }
111             m_handle = handle;
112         }
113         auto currentCommit = GetParameterCommitId(m_handle);
114         PropertyTypeLocker locker(m_propType);
115         if (locker.isLocked()) {
116             if (currentCommit != m_commit) {
117                 updateValue();
118                 m_commit = currentCommit;
119             }
120             return m_value;
121         } else {
122             return getDirectValue();
123         }
124     }
125 private:
getRawValue(char * value,unsigned int len)126     bool getRawValue(char *value, unsigned int len)
127     {
128         auto res = GetParameterValue(m_handle, value, len);
129         if (res < 0) {
130             std::cerr << "CacheData -> GetParameterValue -> Can't get value for key: " << m_key;
131             std::cerr << " handle: " << m_handle << " Result: " << res << "\n";
132             return false;
133         }
134         return true;
135     }
136 
getDirectValue()137     T getDirectValue()
138     {
139         RawPropertyData tempData;
140         if (!getRawValue(tempData.data(), tempData.size())) {
141             return m_defaultValue;
142         }
143         return m_converter(tempData, m_defaultValue);
144     }
145 
updateValue()146     void updateValue()
147     {
148         if (!getRawValue(m_rawData.data(), m_rawData.size())) {
149             m_value = m_defaultValue;
150             return;
151         }
152         m_value = m_converter(m_rawData, m_defaultValue);
153     }
154 
155     RawPropertyData m_rawData = {0};
156     unsigned int m_handle = -1;
157     unsigned int m_commit = -1;
158     T m_value;
159     const T m_defaultValue;
160     const uint32_t m_propType;
161     std::string m_key;
162     DataConverter m_converter;
163 };
164 
165 using SwitchCache = CacheData<bool>;
166 using LogLevelCache = CacheData<uint16_t>;
167 
168 
PropertyGet(const string & key,char * value,int len)169 void PropertyGet(const string &key, char *value, int len)
170 {
171     if (len > HILOG_PROP_VALUE_MAX) {
172         std::cerr << "PropertyGet(): len exceed maximum.\n";
173         return;
174     }
175 
176     auto handle = FindParameter(key.c_str());
177     if (handle == -1) {
178         return;
179     }
180 
181     auto res = GetParameterValue(handle, value, len);
182     if (res < 0) {
183         std::cerr << "PropertyGet() -> GetParameterValue -> Can't get value for key: " << key;
184         std::cerr << " handle: " << handle << " Result: " << res << "\n";
185     }
186 }
187 
PropertySet(const string & key,const char * value)188 void PropertySet(const string &key, const char* value)
189 {
190     auto len = value ? strlen(value) : 0;
191     if (len > HILOG_PROP_VALUE_MAX) {
192         std::cerr << "PropertyGet(): len exceed maximum.\n";
193         return;
194     }
195 
196     auto result = SetParameter(key.c_str(), value);
197     if (result < 0) {
198         if (result == EC_INVALID) {
199             std::cerr << "PropertySet(): Invalid arguments.\n";
200         } else {
201             std::cerr << "PropertySet(): Error: " << result << "\n";
202         }
203     }
204 }
205 
GetProgName()206 string GetProgName()
207 {
208 #ifdef HILOG_USE_MUSL
209     return program_invocation_short_name; /* use HOS interface */
210 #else
211     return getprogname();
212 #endif
213 }
214 
GetPropertyName(uint32_t propType)215 string GetPropertyName(uint32_t propType)
216 {
217     string key;
218     switch (propType) {
219         case PROP_PRIVATE:
220             key = "hilog.private.on";
221             break;
222         case PROP_PROCESS_FLOWCTRL:
223             key = "hilog.flowctrl.pid.on";
224             break;
225         case PROP_DOMAIN_FLOWCTRL:
226             key = "hilog.flowctrl.domain.on";
227             break;
228         case PROP_GLOBAL_LOG_LEVEL:
229             key = "hilog.loggable.global";
230             break;
231         case PROP_DOMAIN_LOG_LEVEL:
232             key = "hilog.loggable.domain.";
233             break;
234         case PROP_TAG_LOG_LEVEL:
235             key = "hilog.loggable.tag.";
236             break;
237         case PROP_SINGLE_DEBUG:
238             key = "hilog.debug.on";
239             break;
240         case PROP_KMSG:
241             key = "persist.sys.hilog.kmsg.on";
242             break;
243         case PROP_PERSIST_DEBUG:
244             key = "persist.sys.hilog.debug.on";
245             break;
246         default:
247             break;
248     }
249     return key;
250 }
251 
LockByProp(uint32_t propType)252 static int LockByProp(uint32_t propType)
253 {
254     switch (propType) {
255         case PROP_PRIVATE:
256             return pthread_mutex_trylock(&g_privateLock);
257         case PROP_PROCESS_FLOWCTRL:
258             return pthread_mutex_trylock(&g_processFlowLock);
259         case PROP_DOMAIN_FLOWCTRL:
260             return pthread_mutex_trylock(&g_domainFlowLock);
261         case PROP_GLOBAL_LOG_LEVEL:
262             return pthread_mutex_trylock(&g_globalLevelLock);
263         case PROP_DOMAIN_LOG_LEVEL:
264             return pthread_mutex_trylock(&g_domainLevelLock);
265         case PROP_TAG_LOG_LEVEL:
266             return pthread_mutex_trylock(&g_tagLevelLock);
267         case PROP_SINGLE_DEBUG:
268             return pthread_mutex_trylock(&g_debugLock);
269         case PROP_KMSG:
270             return pthread_mutex_trylock(&g_kmsgLock);
271         case PROP_PERSIST_DEBUG:
272             return pthread_mutex_trylock(&g_persistDebugLock);
273         default:
274             return -1;
275     }
276 }
277 
UnlockByProp(uint32_t propType)278 static void UnlockByProp(uint32_t propType)
279 {
280     switch (propType) {
281         case PROP_PRIVATE:
282             pthread_mutex_unlock(&g_privateLock);
283             break;
284         case PROP_PROCESS_FLOWCTRL:
285             pthread_mutex_unlock(&g_processFlowLock);
286             break;
287         case PROP_DOMAIN_FLOWCTRL:
288             pthread_mutex_unlock(&g_domainFlowLock);
289             break;
290         case PROP_GLOBAL_LOG_LEVEL:
291             pthread_mutex_unlock(&g_globalLevelLock);
292             break;
293         case PROP_DOMAIN_LOG_LEVEL:
294             pthread_mutex_unlock(&g_domainLevelLock);
295             break;
296         case PROP_TAG_LOG_LEVEL:
297             pthread_mutex_unlock(&g_tagLevelLock);
298             break;
299         case PROP_SINGLE_DEBUG:
300             pthread_mutex_unlock(&g_debugLock);
301             break;
302         case PROP_KMSG:
303             pthread_mutex_unlock(&g_kmsgLock);
304             break;
305         case PROP_PERSIST_DEBUG:
306             pthread_mutex_unlock(&g_persistDebugLock);
307             break;
308         default:
309             break;
310     }
311 }
312 
textToBool(const RawPropertyData & data,bool defaultVal)313 static bool textToBool(const RawPropertyData& data, bool defaultVal)
314 {
315     if (!strcmp(data.data(), "true")) {
316         return true;
317     } else if (!strcmp(data.data(), "false")) {
318         return false;
319     }
320     return defaultVal;
321 }
322 
IsDebugOn()323 bool IsDebugOn()
324 {
325     return IsSingleDebugOn() || IsPersistDebugOn();
326 }
327 
IsSingleDebugOn()328 bool IsSingleDebugOn()
329 {
330     static auto *switchCache = new SwitchCache(textToBool, false, PROP_SINGLE_DEBUG);
331     return switchCache->getValue();
332 }
333 
IsPersistDebugOn()334 bool IsPersistDebugOn()
335 {
336     static auto *switchCache = new SwitchCache(textToBool, false, PROP_PERSIST_DEBUG);
337     return switchCache->getValue();
338 }
339 
IsPrivateSwitchOn()340 bool IsPrivateSwitchOn()
341 {
342     static auto *switchCache = new SwitchCache(textToBool, true, PROP_PRIVATE);
343     return switchCache->getValue();
344 }
345 
IsProcessSwitchOn()346 bool IsProcessSwitchOn()
347 {
348     static auto *switchCache = new SwitchCache(textToBool, false, PROP_PROCESS_FLOWCTRL);
349     return switchCache->getValue();
350 }
351 
IsDomainSwitchOn()352 bool IsDomainSwitchOn()
353 {
354     static auto *switchCache = new SwitchCache(textToBool, false, PROP_DOMAIN_FLOWCTRL);
355     return switchCache->getValue();
356 }
357 
IsKmsgSwitchOn()358 bool IsKmsgSwitchOn()
359 {
360     static auto *switchCache = new SwitchCache(textToBool, false, PROP_KMSG);
361     return switchCache->getValue();
362 }
363 
textToLogLevel(const RawPropertyData & data,uint16_t defaultVal)364 static uint16_t textToLogLevel(const RawPropertyData& data, uint16_t defaultVal)
365 {
366     static const std::unordered_map<char, uint16_t> logLevels = {
367         { 'd', LOG_DEBUG }, { 'D', LOG_DEBUG },
368         { 'i', LOG_INFO }, { 'I', LOG_INFO },
369         { 'w', LOG_WARN }, { 'W', LOG_WARN },
370         { 'e', LOG_ERROR }, { 'E', LOG_ERROR },
371         { 'f', LOG_FATAL }, { 'F', LOG_FATAL },
372     };
373     auto it = logLevels.find(data[0]);
374     if (it != logLevels.end()) {
375         return it->second;
376     }
377     return LOG_LEVEL_MIN;
378 }
379 
GetGlobalLevel()380 uint16_t GetGlobalLevel()
381 {
382     static auto *logLevelCache = new LogLevelCache(textToLogLevel, LOG_LEVEL_MIN, PROP_GLOBAL_LOG_LEVEL);
383     return logLevelCache->getValue();
384 }
385 
GetDomainLevel(uint32_t domain)386 uint16_t GetDomainLevel(uint32_t domain)
387 {
388     static auto *domainMap = new std::unordered_map<uint32_t, LogLevelCache*>();
389     static shared_timed_mutex* mtx = new shared_timed_mutex;
390     std::decay<decltype(*domainMap)>::type::iterator it;
391     {
392         ReadLock lock(*mtx);
393         it = domainMap->find(domain);
394     }
395     if (it == domainMap->end()) { // new domain
396         InsertLock lock(*mtx);
397         it = domainMap->find(domain); // secured for two thread went across above condition
398         if (it == domainMap->end()) {
399             LogLevelCache* levelCache = new LogLevelCache(textToLogLevel, LOG_LEVEL_MIN, PROP_DOMAIN_LOG_LEVEL,
400                 to_string(domain));
401             auto result = domainMap->insert({ domain, levelCache });
402             if (!result.second) {
403                 std::cerr << "Can't insert new LogLevelCache for domain: " << domain << "\n";
404                 return LOG_LEVEL_MIN;
405             }
406             it = result.first;
407         }
408     }
409     LogLevelCache* levelCache = it->second;
410     return levelCache->getValue();
411 }
412 
GetTagLevel(const string & tag)413 uint16_t GetTagLevel(const string& tag)
414 {
415     static auto *tagMap = new std::unordered_map<std::string, LogLevelCache*>();
416     static shared_timed_mutex* mtx = new shared_timed_mutex;
417     std::decay<decltype(*tagMap)>::type::iterator it;
418     {
419         ReadLock lock(*mtx);
420         it = tagMap->find(tag);
421     }
422     if (it == tagMap->end()) { // new tag
423         InsertLock lock(*mtx);
424         it = tagMap->find(tag); // secured for two thread went across above condition
425         if (it == tagMap->end()) {
426             LogLevelCache* levelCache = new LogLevelCache(textToLogLevel, LOG_LEVEL_MIN, PROP_TAG_LOG_LEVEL, tag);
427             auto result = tagMap->insert({ tag, levelCache });
428             if (!result.second) {
429                 std::cerr << "Can't insert new LogLevelCache for tag: " << tag << "\n";
430                 return LOG_LEVEL_MIN;
431             }
432             it = result.first;
433         }
434     }
435     LogLevelCache* levelCache = it->second;
436     return levelCache->getValue();
437 }
438