xref: /aosp_15_r20/system/logging/liblog/properties.cpp (revision 598139dc91b21518d67c408eaea2644226490971)
1 /*
2 ** Copyright 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 <log/log_properties.h>
18 
19 #include <ctype.h>
20 #include <pthread.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include <algorithm>
26 
27 #include <android-base/macros.h>
28 
29 #include <private/android_logger.h>
30 
31 #include "logger_write.h"
32 
33 #ifdef __ANDROID__
34 #include <sys/system_properties.h>
35 
36 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
37 
trylock()38 static bool trylock() {
39   /*
40    * If we trigger a signal handler in the middle of locked activity and the
41    * signal handler logs a message, we could get into a deadlock state.
42    */
43   /*
44    *  Any contention, and we can turn around and use the non-cached method
45    * in less time than the system call associated with a mutex to deal with
46    * the contention.
47    */
48   return pthread_mutex_trylock(&lock_loggable) == 0;
49 }
50 
unlock()51 static void unlock() {
52   pthread_mutex_unlock(&lock_loggable);
53 }
54 
55 struct cache {
56   const prop_info* pinfo;
57   uint32_t serial;
58 };
59 
60 struct cache_char {
61   struct cache cache;
62   unsigned char c;
63 };
64 
check_cache(struct cache * cache)65 static int check_cache(struct cache* cache) {
66   return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial;
67 }
68 
69 #define BOOLEAN_TRUE 0xFF
70 #define BOOLEAN_FALSE 0xFE
71 
refresh_cache(struct cache_char * cache,const char * key)72 static void refresh_cache(struct cache_char* cache, const char* key) {
73   char buf[PROP_VALUE_MAX];
74 
75   if (!cache->cache.pinfo) {
76     cache->cache.pinfo = __system_property_find(key);
77     if (!cache->cache.pinfo) {
78       return;
79     }
80   }
81   cache->cache.serial = __system_property_serial(cache->cache.pinfo);
82   __system_property_read(cache->cache.pinfo, 0, buf);
83   switch (buf[0]) {
84     case 't':
85     case 'T':
86       cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
87       break;
88     case 'f':
89     case 'F':
90       cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
91       break;
92     default:
93       cache->c = buf[0];
94   }
95 }
96 
__android_log_level(const char * tag,size_t tag_len)97 static int __android_log_level(const char* tag, size_t tag_len) {
98   if (tag == nullptr || tag_len == 0) {
99     auto& tag_string = GetDefaultTag();
100     tag = tag_string.c_str();
101     tag_len = tag_string.size();
102   }
103 
104   /*
105    * Single layer cache of four properties. Priorities are:
106    *    log.tag.<tag>
107    *    persist.log.tag.<tag>
108    *    log.tag
109    *    persist.log.tag
110    * Where the missing tag matches all tags and becomes the
111    * system global default. We do not support ro.log.tag* .
112    */
113   static std::string* last_tag = new std::string;
114   static uint32_t global_serial;
115   uint32_t current_global_serial;
116   static cache_char tag_cache[2];
117   static cache_char global_cache[2];
118 
119   static const char* log_namespace = "persist.log.tag.";
120   char key[strlen(log_namespace) + tag_len + 1];
121   strcpy(key, log_namespace);
122 
123   bool locked = trylock();
124   bool change_detected, global_change_detected;
125   global_change_detected = change_detected = !locked;
126 
127   char c = 0;
128   if (locked) {
129     // Check all known serial numbers for changes.
130     for (size_t i = 0; i < arraysize(tag_cache); ++i) {
131       if (check_cache(&tag_cache[i].cache)) {
132         change_detected = true;
133       }
134     }
135     for (size_t i = 0; i < arraysize(global_cache); ++i) {
136       if (check_cache(&global_cache[i].cache)) {
137         global_change_detected = true;
138       }
139     }
140 
141     current_global_serial = __system_property_area_serial();
142     if (current_global_serial != global_serial) {
143       global_change_detected = change_detected = true;
144     }
145   }
146 
147   if (tag_len != 0) {
148     bool local_change_detected = change_detected;
149     if (locked) {
150       // compare() rather than == because tag isn't guaranteed 0-terminated.
151       if (last_tag->compare(0, last_tag->size(), tag, tag_len) != 0) {
152         // Invalidate log.tag.<tag> cache.
153         for (size_t i = 0; i < arraysize(tag_cache); ++i) {
154           tag_cache[i].cache.pinfo = NULL;
155           tag_cache[i].c = '\0';
156         }
157         last_tag->assign(tag, tag_len);
158         local_change_detected = true;
159       }
160     }
161     *stpncpy(key + strlen(log_namespace), tag, tag_len) = '\0';
162 
163     for (size_t i = 0; i < arraysize(tag_cache); ++i) {
164       cache_char* cache = &tag_cache[i];
165       cache_char temp_cache;
166 
167       if (!locked) {
168         temp_cache.cache.pinfo = NULL;
169         temp_cache.c = '\0';
170         cache = &temp_cache;
171       }
172       if (local_change_detected) {
173         refresh_cache(cache, i == 0 ? key : key + strlen("persist."));
174       }
175 
176       if (cache->c) {
177         c = cache->c;
178         break;
179       }
180     }
181   }
182 
183   switch (toupper(c)) { /* if invalid, resort to global */
184     case 'V':
185     case 'D':
186     case 'I':
187     case 'W':
188     case 'E':
189     case 'F': /* Not officially supported */
190     case 'A':
191     case 'S':
192     case BOOLEAN_FALSE: /* Not officially supported */
193       break;
194     default:
195       /* clear '.' after log.tag */
196       key[strlen(log_namespace) - 1] = '\0';
197 
198       for (size_t i = 0; i < arraysize(global_cache); ++i) {
199         cache_char* cache = &global_cache[i];
200         cache_char temp_cache;
201 
202         if (!locked) {
203           temp_cache = *cache;
204           if (temp_cache.cache.pinfo != cache->cache.pinfo) {  // check atomic
205             temp_cache.cache.pinfo = NULL;
206             temp_cache.c = '\0';
207           }
208           cache = &temp_cache;
209         }
210         if (global_change_detected) {
211           refresh_cache(cache, i == 0 ? key : key + strlen("persist."));
212         }
213 
214         if (cache->c) {
215           c = cache->c;
216           break;
217         }
218       }
219       break;
220   }
221 
222   if (locked) {
223     global_serial = current_global_serial;
224     unlock();
225   }
226 
227   switch (toupper(c)) {
228     /* clang-format off */
229     case 'V': return ANDROID_LOG_VERBOSE;
230     case 'D': return ANDROID_LOG_DEBUG;
231     case 'I': return ANDROID_LOG_INFO;
232     case 'W': return ANDROID_LOG_WARN;
233     case 'E': return ANDROID_LOG_ERROR;
234     case 'F': /* FALLTHRU */ /* Not officially supported */
235     case 'A': return ANDROID_LOG_FATAL;
236     case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
237     case 'S': return ANDROID_LOG_SILENT;
238       /* clang-format on */
239   }
240   return -1;
241 }
242 
__android_log_is_loggable_len(int prio,const char * tag,size_t len,int default_prio)243 int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
244   int minimum_log_priority = __android_log_get_minimum_priority();
245   int property_log_level = __android_log_level(tag, len);
246 
247   if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
248     return prio >= std::min(property_log_level, minimum_log_priority);
249   } else if (property_log_level >= 0) {
250     return prio >= property_log_level;
251   } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
252     return prio >= minimum_log_priority;
253   } else {
254     return prio >= default_prio;
255   }
256 }
257 
__android_log_is_loggable(int prio,const char * tag,int default_prio)258 int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
259   auto len = tag ? strlen(tag) : 0;
260   return __android_log_is_loggable_len(prio, tag, len, default_prio);
261 }
262 
__android_log_is_debuggable()263 int __android_log_is_debuggable() {
264   static int is_debuggable = [] {
265     char value[PROP_VALUE_MAX] = {};
266     return __system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1");
267   }();
268 
269   return is_debuggable;
270 }
271 
__android_log_security()272 int __android_log_security() {
273   static pthread_mutex_t security_lock = PTHREAD_MUTEX_INITIALIZER;
274   static cache_char security_prop = {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE};
275   static uint32_t security_serial = 0;
276 
277   if (pthread_mutex_trylock(&security_lock)) {
278     /* We are willing to accept some race in this context */
279     return security_prop.c == BOOLEAN_TRUE;
280   }
281 
282   int change_detected = check_cache(&security_prop.cache);
283   uint32_t current_serial = __system_property_area_serial();
284   if (current_serial != security_serial) {
285     change_detected = 1;
286   }
287   if (change_detected) {
288     refresh_cache(&security_prop, "persist.logd.security");
289     security_serial = current_serial;
290   }
291 
292   int res = security_prop.c == BOOLEAN_TRUE;
293 
294   pthread_mutex_unlock(&security_lock);
295 
296   return res;
297 }
298 
299 #else
300 
__android_log_is_loggable(int prio,const char *,int)301 int __android_log_is_loggable(int prio, const char*, int) {
302   int minimum_priority = __android_log_get_minimum_priority();
303   if (minimum_priority == ANDROID_LOG_DEFAULT) {
304     minimum_priority = ANDROID_LOG_INFO;
305   }
306   return prio >= minimum_priority;
307 }
308 
__android_log_is_loggable_len(int prio,const char *,size_t,int def)309 int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
310   return __android_log_is_loggable(prio, nullptr, def);
311 }
312 
__android_log_is_debuggable()313 int __android_log_is_debuggable() {
314   return 1;
315 }
316 
__android_log_security()317 int __android_log_security() {
318   return 0;
319 }
320 
321 #endif
322