• 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 #include <array>
16 #include <atomic>
17 #include <cassert>
18 #include <climits>
19 #include <cstdio>
20 #include <cstring>
21 #include <ctime>
22 #include <fstream>
23 #include <functional>
24 #include <iostream>
25 #include <pthread.h>
26 #include <shared_mutex>
27 #include <string>
28 #include <sys/uio.h>
29 #include <unistd.h>
30 #include <unordered_map>
31 
32 #include <parameter.h>
33 #include <sysparam_errno.h>
34 #include <hilog/log.h>
35 #include <hilog_common.h>
36 #include <log_utils.h>
37 
38 #include "properties.h"
39 
40 namespace OHOS {
41 namespace HiviewDFX {
42 using namespace std;
43 
44 enum class PropType {
45     // Below properties are used in HiLog API, which will be invoked frequently, so they should be cached
46     PROP_PRIVATE = 0,
47     PROP_ONCE_DEBUG,
48     PROP_PERSIST_DEBUG,
49     PROP_GLOBAL_LOG_LEVEL,
50     PROP_DOMAIN_LOG_LEVEL,
51     PROP_TAG_LOG_LEVEL,
52     PROP_DOMAIN_FLOWCTRL,
53     PROP_PROCESS_FLOWCTRL,
54 
55     // Below properties needn't be cached, used in low frequency
56     PROP_KMSG,
57     PROP_BUFFER_SIZE,
58     PROP_PROC_QUOTA,
59     PROP_STATS_ENABLE,
60     PROP_STATS_TAG_ENABLE,
61     PROP_DOMAIN_QUOTA,
62 
63     PROP_MAX,
64 };
65 using ReadLock = shared_lock<shared_timed_mutex>;
66 using InsertLock = unique_lock<shared_timed_mutex>;
67 
68 static const int HILOG_PROP_VALUE_MAX = 92;
69 static int LockByProp(PropType propType);
70 static void UnlockByProp(PropType propType);
71 
72 static pthread_mutex_t g_privateLock = PTHREAD_MUTEX_INITIALIZER;
73 static pthread_mutex_t g_onceDebugLock = PTHREAD_MUTEX_INITIALIZER;
74 static pthread_mutex_t g_persistDebugLock = PTHREAD_MUTEX_INITIALIZER;
75 static pthread_mutex_t g_globalLevelLock = PTHREAD_MUTEX_INITIALIZER;
76 static pthread_mutex_t g_domainLevelLock = PTHREAD_MUTEX_INITIALIZER;
77 static pthread_mutex_t g_tagLevelLock = PTHREAD_MUTEX_INITIALIZER;
78 static pthread_mutex_t g_domainFlowLock = PTHREAD_MUTEX_INITIALIZER;
79 static pthread_mutex_t g_processFlowLock = PTHREAD_MUTEX_INITIALIZER;
80 static constexpr const char* HAP_DEBUGGABLE = "HAP_DEBUGGABLE";
81 
82 using PropRes = struct {
83     string name;
84     pthread_mutex_t* lock;
85 };
86 static PropRes g_PropResources[static_cast<int>(PropType::PROP_MAX)] = {
87     // Cached:
88     {"hilog.private.on", &g_privateLock}, // PROP_PRIVATE
89     {"hilog.debug.on", &g_onceDebugLock}, // PROP_ONCE_DEBUG
90     {"persist.sys.hilog.debug.on", &g_persistDebugLock}, // PROP_PERSIST_DEBUG
91     {"hilog.loggable.global", &g_globalLevelLock}, // PROP_GLOBAL_LOG_LEVEL
92     {"hilog.loggable.domain.", &g_domainLevelLock}, // PROP_DOMAIN_LOG_LEVEL
93     {"hilog.loggable.tag.", &g_tagLevelLock}, // PROP_TAG_LOG_LEVEL
94     {"hilog.flowctrl.domain.on", &g_domainFlowLock}, // PROP_DOMAIN_FLOWCTRL
95     {"hilog.flowctrl.proc.on", &g_processFlowLock}, // PROP_PROCESS_FLOWCTRL
96 
97     // Non cached:
98     {"persist.sys.hilog.kmsg.on", nullptr}, // PROP_KMSG,
99     {"hilog.buffersize.", nullptr}, // PROP_BUFFER_SIZE,
100     {"hilog.quota.proc.", nullptr}, // PROP_PROC_QUOTA
101     {"persist.sys.hilog.stats", nullptr}, // PROP_STATS_ENABLE,
102     {"persist.sys.hilog.stats.tag", nullptr}, // PROP_STATS_TAG_ENABLE,
103     {"hilog.quota.domain.", nullptr}, // DOMAIN_QUOTA
104 };
105 
GetPropertyName(PropType propType)106 static string GetPropertyName(PropType propType)
107 {
108     return g_PropResources[static_cast<int>(propType)].name;
109 }
110 
LockByProp(PropType propType)111 static int LockByProp(PropType propType)
112 {
113     if (g_PropResources[static_cast<int>(propType)].lock == nullptr) {
114         return -1;
115     }
116     return pthread_mutex_trylock(g_PropResources[static_cast<int>(propType)].lock);
117 }
118 
UnlockByProp(PropType propType)119 static void UnlockByProp(PropType propType)
120 {
121     if (g_PropResources[static_cast<int>(propType)].lock == nullptr) {
122         return;
123     }
124     pthread_mutex_unlock(g_PropResources[static_cast<int>(propType)].lock);
125     return;
126 }
127 
PropertyGet(const string & key,char * value,int len)128 static int PropertyGet(const string &key, char *value, int len)
129 {
130     int handle = static_cast<int>(FindParameter(key.c_str()));
131     if (handle == -1) {
132         return RET_FAIL;
133     }
134 
135     auto res = GetParameterValue(handle, value, len);
136     if (res < 0) {
137         std::cerr << "PropertyGet() -> GetParameterValue -> Can't get value for key: " << key;
138         std::cerr << " handle: " << handle << " Result: " << res << "\n";
139         return RET_FAIL;
140     }
141     return RET_SUCCESS;
142 }
143 
PropertySet(const string & key,const string & value)144 static int PropertySet(const string &key, const string &value)
145 {
146     auto result = SetParameter(key.c_str(), value.c_str());
147     if (result < 0) {
148         if (result == EC_INVALID) {
149             std::cerr << "PropertySet(): Invalid arguments.\n";
150         } else {
151             std::cerr << "PropertySet(): key: " << key.c_str() << ", value: " << value <<
152             ",  error: " << result << "\n";
153         }
154         return RET_FAIL;
155     }
156     return RET_SUCCESS;
157 }
158 
159 class PropertyTypeLocker {
160 public:
PropertyTypeLocker(PropType propType)161     explicit PropertyTypeLocker(PropType propType) : m_propType(propType), m_isLocked(false)
162     {
163         m_isLocked = !LockByProp(m_propType);
164     }
165 
~PropertyTypeLocker()166     ~PropertyTypeLocker()
167     {
168         if (m_isLocked) {
169             UnlockByProp(m_propType);
170         }
171     }
172 
isLocked() const173     bool isLocked() const
174     {
175         return m_isLocked;
176     }
177 
178 private:
179     PropType m_propType;
180     bool m_isLocked;
181 };
182 
183 using RawPropertyData = std::array<char, HILOG_PROP_VALUE_MAX>;
184 
185 template<typename T>
186 class CacheData {
187 public:
188     using DataConverter = std::function<T(const RawPropertyData&, const T& defaultVal)>;
189 
CacheData(DataConverter converter,const T & defaultValue,PropType propType,const std::string & suffix="")190     CacheData(DataConverter converter, const T& defaultValue, PropType propType, const std::string& suffix = "")
191         : m_value(defaultValue), m_defaultValue(defaultValue), m_propType(propType), m_converter(converter)
192     {
193         m_key = GetPropertyName(m_propType) + suffix;
194     }
195 
getValue()196     T getValue()
197     {
198         long long sysCommitId = GetSystemCommitId();
199         if (sysCommitId == m_sysCommit) {
200             return m_value;
201         }
202         m_sysCommit = sysCommitId;
203         if (m_handle == -1) {
204             int handle = static_cast<int>(FindParameter(m_key.c_str()));
205             if (handle == -1) {
206                 return m_defaultValue;
207             }
208             m_handle = handle;
209         }
210         int currentCommit = static_cast<int>(GetParameterCommitId(m_handle));
211         PropertyTypeLocker locker(m_propType);
212         if (locker.isLocked()) {
213             if (currentCommit != m_commit) {
214                 updateValue();
215                 m_commit = currentCommit;
216             }
217             return m_value;
218         } else {
219             return getDirectValue();
220         }
221     }
222 
223 private:
getRawValue(char * value,unsigned int len)224     bool getRawValue(char *value, unsigned int len)
225     {
226         auto res = GetParameterValue(m_handle, value, len);
227         if (res < 0) {
228             std::cerr << "CacheData -> GetParameterValue -> Can't get value for key: " << m_key;
229             std::cerr << " handle: " << m_handle << " Result: " << res << "\n";
230             return false;
231         }
232         return true;
233     }
234 
getDirectValue()235     T getDirectValue()
236     {
237         RawPropertyData tempData;
238         if (!getRawValue(tempData.data(), tempData.size())) {
239             return m_defaultValue;
240         }
241         m_value = m_converter(tempData, m_defaultValue);
242         return m_value;
243     }
244 
updateValue()245     void updateValue()
246     {
247         RawPropertyData rawData = {0};
248         if (!getRawValue(rawData.data(), rawData.size())) {
249             m_value = m_defaultValue;
250             return;
251         }
252         m_value = m_converter(rawData, m_defaultValue);
253     }
254 
255     int m_handle = -1;
256     int m_commit = -1;
257     long long m_sysCommit = -1;
258     T m_value;
259     const T m_defaultValue;
260     const PropType m_propType;
261     std::string m_key;
262     DataConverter m_converter;
263 };
264 
265 using SwitchCache = CacheData<bool>;
266 using LogLevelCache = CacheData<uint16_t>;
267 
TextToBool(const RawPropertyData & data,bool defaultVal)268 static bool TextToBool(const RawPropertyData& data, bool defaultVal)
269 {
270     if (!strcmp(data.data(), "true")) {
271         return true;
272     } else if (!strcmp(data.data(), "false")) {
273         return false;
274     }
275     return defaultVal;
276 }
277 
TextToLogLevel(const RawPropertyData & data,uint16_t defaultVal)278 static uint16_t TextToLogLevel(const RawPropertyData& data, uint16_t defaultVal)
279 {
280     uint16_t level = PrettyStr2LogLevel(data.data());
281     if (level == LOG_LEVEL_MIN) {
282         level = defaultVal;
283     }
284     return level;
285 }
286 
IsPrivateSwitchOn()287 bool IsPrivateSwitchOn()
288 {
289     static auto *switchCache = new SwitchCache(TextToBool, true, PropType::PROP_PRIVATE);
290     if (switchCache == nullptr) {
291         return false;
292     }
293     return switchCache->getValue();
294 }
295 
IsOnceDebugOn()296 bool IsOnceDebugOn()
297 {
298     static auto *switchCache = new SwitchCache(TextToBool, false, PropType::PROP_ONCE_DEBUG);
299     if (switchCache == nullptr) {
300         return false;
301     }
302     return switchCache->getValue();
303 }
304 
IsPersistDebugOn()305 bool IsPersistDebugOn()
306 {
307     static auto *switchCache = new SwitchCache(TextToBool, false, PropType::PROP_PERSIST_DEBUG);
308     if (switchCache == nullptr) {
309         return false;
310     }
311     return switchCache->getValue();
312 }
313 
IsDebugOn()314 bool IsDebugOn()
315 {
316     return IsOnceDebugOn() || IsPersistDebugOn();
317 }
318 
IsDebuggableHap()319 bool IsDebuggableHap()
320 {
321     const char *path = getenv(HAP_DEBUGGABLE);
322     if ((path == nullptr) || (strcmp(path, "true") != 0)) {
323         return false;
324     }
325     return true;
326 }
327 
GetGlobalLevel()328 uint16_t GetGlobalLevel()
329 {
330     static auto *logLevelCache = new LogLevelCache(TextToLogLevel, LOG_LEVEL_MIN, PropType::PROP_GLOBAL_LOG_LEVEL);
331     return logLevelCache->getValue();
332 }
333 
GetDomainLevel(uint32_t domain)334 uint16_t GetDomainLevel(uint32_t domain)
335 {
336     static auto *domainMap = new std::unordered_map<uint32_t, LogLevelCache*>();
337     static shared_timed_mutex* mtx = new shared_timed_mutex;
338     std::decay<decltype(*domainMap)>::type::iterator it;
339     {
340         ReadLock lock(*mtx);
341         it = domainMap->find(domain);
342     }
343     if (it == domainMap->end()) { // new domain
344         InsertLock lock(*mtx);
345         it = domainMap->find(domain); // secured for two thread went across above condition
346         if (it == domainMap->end()) {
347             LogLevelCache* levelCache = new LogLevelCache(TextToLogLevel, LOG_LEVEL_MIN,
348             PropType::PROP_DOMAIN_LOG_LEVEL, Uint2HexStr(domain));
349             auto result = domainMap->insert({ domain, levelCache });
350             if (!result.second) {
351                 delete levelCache;
352                 return LOG_LEVEL_MIN;
353             }
354             it = result.first;
355         }
356     }
357     LogLevelCache* levelCache = it->second;
358     return levelCache->getValue();
359 }
360 
GetTagLevel(const string & tag)361 uint16_t GetTagLevel(const string& tag)
362 {
363     static auto *tagMap = new std::unordered_map<std::string, LogLevelCache*>();
364     static shared_timed_mutex* mtx = new shared_timed_mutex;
365     std::decay<decltype(*tagMap)>::type::iterator it;
366     {
367         ReadLock lock(*mtx);
368         it = tagMap->find(tag);
369     }
370     if (it == tagMap->end()) { // new tag
371         InsertLock lock(*mtx);
372         it = tagMap->find(tag); // secured for two thread went across above condition
373         if (it == tagMap->end()) {
374             LogLevelCache* levelCache = new LogLevelCache(TextToLogLevel, LOG_LEVEL_MIN,
375             PropType::PROP_TAG_LOG_LEVEL, tag);
376             auto result = tagMap->insert({ tag, levelCache });
377             if (!result.second) {
378                 delete levelCache;
379                 return LOG_LEVEL_MIN;
380             }
381             it = result.first;
382         }
383     }
384     LogLevelCache* levelCache = it->second;
385     return levelCache->getValue();
386 }
387 
IsProcessSwitchOn()388 bool IsProcessSwitchOn()
389 {
390     static auto *switchCache = new SwitchCache(TextToBool, false, PropType::PROP_PROCESS_FLOWCTRL);
391     if (switchCache == nullptr) {
392         return false;
393     }
394     return switchCache->getValue();
395 }
396 
IsDomainSwitchOn()397 bool IsDomainSwitchOn()
398 {
399     static auto *switchCache = new SwitchCache(TextToBool, false, PropType::PROP_DOMAIN_FLOWCTRL);
400     if (switchCache == nullptr) {
401         return false;
402     }
403     return switchCache->getValue();
404 }
405 
IsKmsgSwitchOn()406 bool IsKmsgSwitchOn()
407 {
408     RawPropertyData rawData;
409     int ret = PropertyGet(GetPropertyName(PropType::PROP_KMSG), rawData.data(), HILOG_PROP_VALUE_MAX);
410     if (ret == RET_FAIL) {
411         return false;
412     }
413     return TextToBool(rawData, false);
414 }
415 
GetBufferSizePropName(uint16_t type,bool persist)416 static string GetBufferSizePropName(uint16_t type, bool persist)
417 {
418     string name = persist ? "persist.sys." : "";
419     string suffix;
420 
421     if (type >= LOG_TYPE_MAX) {
422         suffix = "global";
423     } else {
424         suffix = LogType2Str(type);
425     }
426 
427     return name + GetPropertyName(PropType::PROP_BUFFER_SIZE) + suffix;
428 }
429 
GetBufferSize(uint16_t type,bool persist)430 size_t GetBufferSize(uint16_t type, bool persist)
431 {
432     char value[HILOG_PROP_VALUE_MAX] = {0};
433 
434     if (type > LOG_TYPE_MAX || type < LOG_TYPE_MIN) {
435         return 0;
436     }
437 
438     int ret = PropertyGet(GetBufferSizePropName(type, persist), value, HILOG_PROP_VALUE_MAX);
439     if (ret == RET_FAIL || value[0] == 0) {
440         return 0;
441     }
442 
443     return std::stoi(value);
444 }
445 
IsStatsEnable()446 bool IsStatsEnable()
447 {
448     RawPropertyData rawData;
449     int ret = PropertyGet(GetPropertyName(PropType::PROP_STATS_ENABLE), rawData.data(), HILOG_PROP_VALUE_MAX);
450     if (ret == RET_FAIL) {
451         return false;
452     }
453     return TextToBool(rawData, false);
454 }
455 
IsTagStatsEnable()456 bool IsTagStatsEnable()
457 {
458     RawPropertyData rawData;
459     int ret = PropertyGet(GetPropertyName(PropType::PROP_STATS_TAG_ENABLE), rawData.data(), HILOG_PROP_VALUE_MAX);
460     if (ret == RET_FAIL) {
461         return false;
462     }
463     return TextToBool(rawData, false);
464 }
465 
GetProcessQuota(const string & proc)466 int GetProcessQuota(const string& proc)
467 {
468     static constexpr int default_quota = 10240;
469     char value[HILOG_PROP_VALUE_MAX] = {0};
470     string prop = GetPropertyName(PropType::PROP_PROC_QUOTA) + proc;
471 
472     int ret = PropertyGet(prop, value, HILOG_PROP_VALUE_MAX);
473     if (ret == RET_FAIL || value[0] == 0) {
474         return default_quota;
475     }
476     return std::stoi(value);
477 }
478 
GetDomainQuota(uint32_t domain)479 int GetDomainQuota(uint32_t domain)
480 {
481     static constexpr int default_quota = 10240;
482     char value[HILOG_PROP_VALUE_MAX] = {0};
483     string prop = GetPropertyName(PropType::PROP_DOMAIN_QUOTA) + Uint2HexStr(domain);
484 
485     int ret = PropertyGet(prop, value, HILOG_PROP_VALUE_MAX);
486     if (ret == RET_FAIL || value[0] == 0) {
487         return default_quota;
488     }
489     return std::stoi(value);
490 }
491 
SetBoolValue(PropType type,bool val)492 static int SetBoolValue(PropType type, bool val)
493 {
494     string key = GetPropertyName(type);
495     return key == "" ? RET_FAIL : (PropertySet(key, val ? "true" : "false"));
496 }
497 
SetLevel(PropType type,const string & suffix,uint16_t lvl)498 static int SetLevel(PropType type, const string& suffix, uint16_t lvl)
499 {
500     string key = GetPropertyName(type) + suffix;
501     return key == "" ? RET_FAIL : (PropertySet(key, LogLevel2ShortStr(lvl)));
502 }
503 
SetPrivateSwitchOn(bool on)504 int SetPrivateSwitchOn(bool on)
505 {
506     return SetBoolValue(PropType::PROP_PRIVATE, on);
507 }
508 
SetOnceDebugOn(bool on)509 int SetOnceDebugOn(bool on)
510 {
511     return SetBoolValue(PropType::PROP_ONCE_DEBUG, on);
512 }
513 
SetPersistDebugOn(bool on)514 int SetPersistDebugOn(bool on)
515 {
516     return SetBoolValue(PropType::PROP_PERSIST_DEBUG, on);
517 }
518 
SetGlobalLevel(uint16_t lvl)519 int SetGlobalLevel(uint16_t lvl)
520 {
521     return SetLevel(PropType::PROP_GLOBAL_LOG_LEVEL, "", lvl);
522 }
523 
SetTagLevel(const std::string & tag,uint16_t lvl)524 int SetTagLevel(const std::string& tag, uint16_t lvl)
525 {
526     return SetLevel(PropType::PROP_TAG_LOG_LEVEL, tag, lvl);
527 }
528 
SetDomainLevel(uint32_t domain,uint16_t lvl)529 int SetDomainLevel(uint32_t domain, uint16_t lvl)
530 {
531     return SetLevel(PropType::PROP_DOMAIN_LOG_LEVEL, Uint2HexStr(domain), lvl);
532 }
533 
SetProcessSwitchOn(bool on)534 int SetProcessSwitchOn(bool on)
535 {
536     return SetBoolValue(PropType::PROP_PROCESS_FLOWCTRL, on);
537 }
538 
SetDomainSwitchOn(bool on)539 int SetDomainSwitchOn(bool on)
540 {
541     return SetBoolValue(PropType::PROP_DOMAIN_FLOWCTRL, on);
542 }
543 
SetKmsgSwitchOn(bool on)544 int SetKmsgSwitchOn(bool on)
545 {
546     return SetBoolValue(PropType::PROP_KMSG, on);
547 }
548 
SetBufferSize(uint16_t type,bool persist,size_t size)549 int SetBufferSize(uint16_t type, bool persist, size_t size)
550 {
551     if (type > LOG_TYPE_MAX || type < LOG_TYPE_MIN) {
552         return RET_FAIL;
553     }
554     return PropertySet(GetBufferSizePropName(type, persist), to_string(size));
555 }
556 } // namespace HiviewDFX
557 } // namespace OHOS