• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <private/android_logger.h>
28 
29 #include "logger_write.h"
30 
31 #ifdef __ANDROID__
32 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
33 #include <sys/_system_properties.h>
34 
35 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
36 
lock()37 static int lock() {
38   /*
39    * If we trigger a signal handler in the middle of locked activity and the
40    * signal handler logs a message, we could get into a deadlock state.
41    */
42   /*
43    *  Any contention, and we can turn around and use the non-cached method
44    * in less time than the system call associated with a mutex to deal with
45    * the contention.
46    */
47   return pthread_mutex_trylock(&lock_loggable);
48 }
49 
unlock()50 static void unlock() {
51   pthread_mutex_unlock(&lock_loggable);
52 }
53 
54 struct cache {
55   const prop_info* pinfo;
56   uint32_t serial;
57 };
58 
59 struct cache_char {
60   struct cache cache;
61   unsigned char c;
62 };
63 
check_cache(struct cache * cache)64 static int check_cache(struct cache* cache) {
65   return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial;
66 }
67 
68 #define BOOLEAN_TRUE 0xFF
69 #define BOOLEAN_FALSE 0xFE
70 
refresh_cache(struct cache_char * cache,const char * key)71 static void refresh_cache(struct cache_char* cache, const char* key) {
72   char buf[PROP_VALUE_MAX];
73 
74   if (!cache->cache.pinfo) {
75     cache->cache.pinfo = __system_property_find(key);
76     if (!cache->cache.pinfo) {
77       return;
78     }
79   }
80   cache->cache.serial = __system_property_serial(cache->cache.pinfo);
81   __system_property_read(cache->cache.pinfo, 0, buf);
82   switch (buf[0]) {
83     case 't':
84     case 'T':
85       cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
86       break;
87     case 'f':
88     case 'F':
89       cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
90       break;
91     default:
92       cache->c = buf[0];
93   }
94 }
95 
__android_log_level(const char * tag,size_t len)96 static int __android_log_level(const char* tag, size_t len) {
97   /* sizeof() is used on this array below */
98   static const char log_namespace[] = "persist.log.tag.";
99   static const size_t base_offset = 8; /* skip "persist." */
100 
101   if (tag == nullptr || len == 0) {
102     auto& tag_string = GetDefaultTag();
103     tag = tag_string.c_str();
104     len = tag_string.size();
105   }
106 
107   /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
108   char key[sizeof(log_namespace) + len];
109   char* kp;
110   size_t i;
111   char c = 0;
112   /*
113    * Single layer cache of four properties. Priorities are:
114    *    log.tag.<tag>
115    *    persist.log.tag.<tag>
116    *    log.tag
117    *    persist.log.tag
118    * Where the missing tag matches all tags and becomes the
119    * system global default. We do not support ro.log.tag* .
120    */
121   static char* last_tag;
122   static size_t last_tag_len;
123   static uint32_t global_serial;
124   /* some compilers erroneously see uninitialized use. !not_locked */
125   uint32_t current_global_serial = 0;
126   static struct cache_char tag_cache[2];
127   static struct cache_char global_cache[2];
128   int change_detected;
129   int global_change_detected;
130   int not_locked;
131 
132   strcpy(key, log_namespace);
133 
134   global_change_detected = change_detected = not_locked = lock();
135 
136   if (!not_locked) {
137     /*
138      *  check all known serial numbers to changes.
139      */
140     for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
141       if (check_cache(&tag_cache[i].cache)) {
142         change_detected = 1;
143       }
144     }
145     for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
146       if (check_cache(&global_cache[i].cache)) {
147         global_change_detected = 1;
148       }
149     }
150 
151     current_global_serial = __system_property_area_serial();
152     if (current_global_serial != global_serial) {
153       change_detected = 1;
154       global_change_detected = 1;
155     }
156   }
157 
158   if (len) {
159     int local_change_detected = change_detected;
160     if (!not_locked) {
161       if (!last_tag || !last_tag[0] || (last_tag[0] != tag[0]) ||
162           strncmp(last_tag + 1, tag + 1, last_tag_len - 1)) {
163         /* invalidate log.tag.<tag> cache */
164         for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
165           tag_cache[i].cache.pinfo = NULL;
166           tag_cache[i].c = '\0';
167         }
168         if (last_tag) last_tag[0] = '\0';
169         local_change_detected = 1;
170       }
171       if (!last_tag || !last_tag[0]) {
172         if (!last_tag) {
173           last_tag = static_cast<char*>(calloc(1, len + 1));
174           last_tag_len = 0;
175           if (last_tag) last_tag_len = len + 1;
176         } else if (len >= last_tag_len) {
177           last_tag = static_cast<char*>(realloc(last_tag, len + 1));
178           last_tag_len = 0;
179           if (last_tag) last_tag_len = len + 1;
180         }
181         if (last_tag) {
182           strncpy(last_tag, tag, len);
183           last_tag[len] = '\0';
184         }
185       }
186     }
187     strncpy(key + sizeof(log_namespace) - 1, tag, len);
188     key[sizeof(log_namespace) - 1 + len] = '\0';
189 
190     kp = key;
191     for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
192       struct cache_char* cache = &tag_cache[i];
193       struct cache_char temp_cache;
194 
195       if (not_locked) {
196         temp_cache.cache.pinfo = NULL;
197         temp_cache.c = '\0';
198         cache = &temp_cache;
199       }
200       if (local_change_detected) {
201         refresh_cache(cache, kp);
202       }
203 
204       if (cache->c) {
205         c = cache->c;
206         break;
207       }
208 
209       kp = key + base_offset;
210     }
211   }
212 
213   switch (toupper(c)) { /* if invalid, resort to global */
214     case 'V':
215     case 'D':
216     case 'I':
217     case 'W':
218     case 'E':
219     case 'F': /* Not officially supported */
220     case 'A':
221     case 'S':
222     case BOOLEAN_FALSE: /* Not officially supported */
223       break;
224     default:
225       /* clear '.' after log.tag */
226       key[sizeof(log_namespace) - 2] = '\0';
227 
228       kp = key;
229       for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
230         struct cache_char* cache = &global_cache[i];
231         struct cache_char temp_cache;
232 
233         if (not_locked) {
234           temp_cache = *cache;
235           if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
236             temp_cache.cache.pinfo = NULL;
237             temp_cache.c = '\0';
238           }
239           cache = &temp_cache;
240         }
241         if (global_change_detected) {
242           refresh_cache(cache, kp);
243         }
244 
245         if (cache->c) {
246           c = cache->c;
247           break;
248         }
249 
250         kp = key + base_offset;
251       }
252       break;
253   }
254 
255   if (!not_locked) {
256     global_serial = current_global_serial;
257     unlock();
258   }
259 
260   switch (toupper(c)) {
261     /* clang-format off */
262     case 'V': return ANDROID_LOG_VERBOSE;
263     case 'D': return ANDROID_LOG_DEBUG;
264     case 'I': return ANDROID_LOG_INFO;
265     case 'W': return ANDROID_LOG_WARN;
266     case 'E': return ANDROID_LOG_ERROR;
267     case 'F': /* FALLTHRU */ /* Not officially supported */
268     case 'A': return ANDROID_LOG_FATAL;
269     case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
270     case 'S': return ANDROID_LOG_SILENT;
271       /* clang-format on */
272   }
273   return -1;
274 }
275 
__android_log_is_loggable_len(int prio,const char * tag,size_t len,int default_prio)276 int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
277   int minimum_log_priority = __android_log_get_minimum_priority();
278   int property_log_level = __android_log_level(tag, len);
279 
280   if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
281     return prio >= std::min(property_log_level, minimum_log_priority);
282   } else if (property_log_level >= 0) {
283     return prio >= property_log_level;
284   } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
285     return prio >= minimum_log_priority;
286   } else {
287     return prio >= default_prio;
288   }
289 }
290 
__android_log_is_loggable(int prio,const char * tag,int default_prio)291 int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
292   auto len = tag ? strlen(tag) : 0;
293   return __android_log_is_loggable_len(prio, tag, len, default_prio);
294 }
295 
__android_log_is_debuggable()296 int __android_log_is_debuggable() {
297   static uint32_t serial;
298   static struct cache_char tag_cache;
299   static const char key[] = "ro.debuggable";
300   int ret;
301 
302   if (tag_cache.c) { /* ro property does not change after set */
303     ret = tag_cache.c == '1';
304   } else if (lock()) {
305     struct cache_char temp_cache = {{NULL, 0xFFFFFFFF}, '\0'};
306     refresh_cache(&temp_cache, key);
307     ret = temp_cache.c == '1';
308   } else {
309     int change_detected = check_cache(&tag_cache.cache);
310     uint32_t current_serial = __system_property_area_serial();
311     if (current_serial != serial) {
312       change_detected = 1;
313     }
314     if (change_detected) {
315       refresh_cache(&tag_cache, key);
316       serial = current_serial;
317     }
318     ret = tag_cache.c == '1';
319 
320     unlock();
321   }
322 
323   return ret;
324 }
325 
326 /*
327  * For properties that are read often, but generally remain constant.
328  * Since a change is rare, we will accept a trylock failure gracefully.
329  * Use a separate lock from is_loggable to keep contention down b/25563384.
330  */
331 struct cache2_char {
332   pthread_mutex_t lock;
333   uint32_t serial;
334   const char* key_persist;
335   struct cache_char cache_persist;
336   const char* key_ro;
337   struct cache_char cache_ro;
338   unsigned char (*const evaluate)(const struct cache2_char* self);
339 };
340 
do_cache2_char(struct cache2_char * self)341 static inline unsigned char do_cache2_char(struct cache2_char* self) {
342   uint32_t current_serial;
343   int change_detected;
344   unsigned char c;
345 
346   if (pthread_mutex_trylock(&self->lock)) {
347     /* We are willing to accept some race in this context */
348     return self->evaluate(self);
349   }
350 
351   change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache);
352   current_serial = __system_property_area_serial();
353   if (current_serial != self->serial) {
354     change_detected = 1;
355   }
356   if (change_detected) {
357     refresh_cache(&self->cache_persist, self->key_persist);
358     refresh_cache(&self->cache_ro, self->key_ro);
359     self->serial = current_serial;
360   }
361   c = self->evaluate(self);
362 
363   pthread_mutex_unlock(&self->lock);
364 
365   return c;
366 }
367 
evaluate_persist_ro(const struct cache2_char * self)368 static unsigned char evaluate_persist_ro(const struct cache2_char* self) {
369   unsigned char c = self->cache_persist.c;
370 
371   if (c) {
372     return c;
373   }
374 
375   return self->cache_ro.c;
376 }
377 
378 /*
379  * Timestamp state generally remains constant, but can change at any time
380  * to handle developer requirements.
381  */
android_log_clockid()382 clockid_t android_log_clockid() {
383   static struct cache2_char clockid = {PTHREAD_MUTEX_INITIALIZER, 0,
384                                        "persist.logd.timestamp",  {{NULL, 0xFFFFFFFF}, '\0'},
385                                        "ro.logd.timestamp",       {{NULL, 0xFFFFFFFF}, '\0'},
386                                        evaluate_persist_ro};
387 
388   return (tolower(do_cache2_char(&clockid)) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
389 }
390 
391 /*
392  * Security state generally remains constant, but the DO must be able
393  * to turn off logging should it become spammy after an attack is detected.
394  */
evaluate_security(const struct cache2_char * self)395 static unsigned char evaluate_security(const struct cache2_char* self) {
396   unsigned char c = self->cache_ro.c;
397 
398   return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
399 }
400 
__android_log_security()401 int __android_log_security() {
402   static struct cache2_char security = {
403       PTHREAD_MUTEX_INITIALIZER, 0,
404       "persist.logd.security",   {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
405       "ro.organization_owned",   {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
406       evaluate_security};
407 
408   return do_cache2_char(&security);
409 }
410 
411 /*
412  * Interface that represents the logd buffer size determination so that others
413  * need not guess our intentions.
414  */
415 
416 /* Property helper */
check_flag(const char * prop,const char * flag)417 static bool check_flag(const char* prop, const char* flag) {
418   const char* cp = strcasestr(prop, flag);
419   if (!cp) {
420     return false;
421   }
422   /* We only will document comma (,) */
423   static const char sep[] = ",:;|+ \t\f";
424   if ((cp != prop) && !strchr(sep, cp[-1])) {
425     return false;
426   }
427   cp += strlen(flag);
428   return !*cp || !!strchr(sep, *cp);
429 }
430 
431 /* cache structure */
432 struct cache_property {
433   struct cache cache;
434   char property[PROP_VALUE_MAX];
435 };
436 
refresh_cache_property(struct cache_property * cache,const char * key)437 static void refresh_cache_property(struct cache_property* cache, const char* key) {
438   if (!cache->cache.pinfo) {
439     cache->cache.pinfo = __system_property_find(key);
440     if (!cache->cache.pinfo) {
441       return;
442     }
443   }
444   cache->cache.serial = __system_property_serial(cache->cache.pinfo);
445   __system_property_read(cache->cache.pinfo, 0, cache->property);
446 }
447 
448 /* get boolean with the logger twist that supports eng adjustments */
__android_logger_property_get_bool(const char * key,int flag)449 bool __android_logger_property_get_bool(const char* key, int flag) {
450   struct cache_property property = {{NULL, 0xFFFFFFFF}, {0}};
451   if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
452     char newkey[strlen("persist.") + strlen(key) + 1];
453     snprintf(newkey, sizeof(newkey), "ro.%s", key);
454     refresh_cache_property(&property, newkey);
455     property.cache.pinfo = NULL;
456     property.cache.serial = 0xFFFFFFFF;
457     snprintf(newkey, sizeof(newkey), "persist.%s", key);
458     refresh_cache_property(&property, newkey);
459     property.cache.pinfo = NULL;
460     property.cache.serial = 0xFFFFFFFF;
461   }
462 
463   refresh_cache_property(&property, key);
464 
465   if (check_flag(property.property, "true")) {
466     return true;
467   }
468   if (check_flag(property.property, "false")) {
469     return false;
470   }
471   if (property.property[0]) {
472     flag &= ~(BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
473   }
474   if (check_flag(property.property, "eng")) {
475     flag |= BOOL_DEFAULT_FLAG_ENG;
476   }
477   /* this is really a "not" flag */
478   if (check_flag(property.property, "svelte")) {
479     flag |= BOOL_DEFAULT_FLAG_SVELTE;
480   }
481 
482   /* Sanity Check */
483   if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
484     flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
485     flag |= BOOL_DEFAULT_TRUE;
486   }
487 
488   if ((flag & BOOL_DEFAULT_FLAG_SVELTE) &&
489       __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE)) {
490     return false;
491   }
492   if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) {
493     return false;
494   }
495 
496   return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
497 }
498 
__android_logger_valid_buffer_size(unsigned long value)499 bool __android_logger_valid_buffer_size(unsigned long value) {
500   static long pages, pagesize;
501   unsigned long maximum;
502 
503   if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
504     return false;
505   }
506 
507   if (!pages) {
508     pages = sysconf(_SC_PHYS_PAGES);
509   }
510   if (pages < 1) {
511     return true;
512   }
513 
514   if (!pagesize) {
515     pagesize = sysconf(_SC_PAGESIZE);
516     if (pagesize <= 1) {
517       pagesize = PAGE_SIZE;
518     }
519   }
520 
521   /* maximum memory impact a somewhat arbitrary ~3% */
522   pages = (pages + 31) / 32;
523   maximum = pages * pagesize;
524 
525   if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
526     return true;
527   }
528 
529   return value <= maximum;
530 }
531 
532 struct cache2_property_size {
533   pthread_mutex_t lock;
534   uint32_t serial;
535   const char* key_persist;
536   struct cache_property cache_persist;
537   const char* key_ro;
538   struct cache_property cache_ro;
539   unsigned long (*const evaluate)(const struct cache2_property_size* self);
540 };
541 
do_cache2_property_size(struct cache2_property_size * self)542 static inline unsigned long do_cache2_property_size(struct cache2_property_size* self) {
543   uint32_t current_serial;
544   int change_detected;
545   unsigned long v;
546 
547   if (pthread_mutex_trylock(&self->lock)) {
548     /* We are willing to accept some race in this context */
549     return self->evaluate(self);
550   }
551 
552   change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache);
553   current_serial = __system_property_area_serial();
554   if (current_serial != self->serial) {
555     change_detected = 1;
556   }
557   if (change_detected) {
558     refresh_cache_property(&self->cache_persist, self->key_persist);
559     refresh_cache_property(&self->cache_ro, self->key_ro);
560     self->serial = current_serial;
561   }
562   v = self->evaluate(self);
563 
564   pthread_mutex_unlock(&self->lock);
565 
566   return v;
567 }
568 
property_get_size_from_cache(const struct cache_property * cache)569 static unsigned long property_get_size_from_cache(const struct cache_property* cache) {
570   char* cp;
571   unsigned long value = strtoul(cache->property, &cp, 10);
572 
573   switch (*cp) {
574     case 'm':
575     case 'M':
576       value *= 1024;
577       [[fallthrough]];
578     case 'k':
579     case 'K':
580       value *= 1024;
581       [[fallthrough]];
582     case '\0':
583       break;
584 
585     default:
586       value = 0;
587   }
588 
589   if (!__android_logger_valid_buffer_size(value)) {
590     value = 0;
591   }
592 
593   return value;
594 }
595 
evaluate_property_get_size(const struct cache2_property_size * self)596 static unsigned long evaluate_property_get_size(const struct cache2_property_size* self) {
597   unsigned long size = property_get_size_from_cache(&self->cache_persist);
598   if (size) {
599     return size;
600   }
601   return property_get_size_from_cache(&self->cache_ro);
602 }
603 
__android_logger_get_buffer_size(log_id_t logId)604 unsigned long __android_logger_get_buffer_size(log_id_t logId) {
605   static const char global_tunable[] = "persist.logd.size"; /* Settings App */
606   static const char global_default[] = "ro.logd.size";      /* BoardConfig.mk */
607   static struct cache2_property_size global = {
608       /* clang-format off */
609     PTHREAD_MUTEX_INITIALIZER, 0,
610     global_tunable, { { NULL, 0xFFFFFFFF }, {} },
611     global_default, { { NULL, 0xFFFFFFFF }, {} },
612     evaluate_property_get_size
613       /* clang-format on */
614   };
615   char key_persist[strlen(global_tunable) + strlen(".security") + 1];
616   char key_ro[strlen(global_default) + strlen(".security") + 1];
617   struct cache2_property_size local = {
618       /* clang-format off */
619     PTHREAD_MUTEX_INITIALIZER, 0,
620     key_persist, { { NULL, 0xFFFFFFFF }, {} },
621     key_ro,      { { NULL, 0xFFFFFFFF }, {} },
622     evaluate_property_get_size
623       /* clang-format on */
624   };
625   unsigned long property_size, default_size;
626 
627   default_size = do_cache2_property_size(&global);
628   if (!default_size) {
629     default_size = __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE)
630                        ? LOG_BUFFER_MIN_SIZE /* 64K  */
631                        : LOG_BUFFER_SIZE;    /* 256K */
632   }
633 
634   snprintf(key_persist, sizeof(key_persist), "%s.%s", global_tunable,
635            android_log_id_to_name(logId));
636   snprintf(key_ro, sizeof(key_ro), "%s.%s", global_default, android_log_id_to_name(logId));
637   property_size = do_cache2_property_size(&local);
638 
639   if (!property_size) {
640     property_size = default_size;
641   }
642 
643   if (!property_size) {
644     property_size = LOG_BUFFER_SIZE;
645   }
646 
647   return property_size;
648 }
649 
650 #else
651 
__android_log_is_loggable(int prio,const char *,int)652 int __android_log_is_loggable(int prio, const char*, int) {
653   int minimum_priority = __android_log_get_minimum_priority();
654   if (minimum_priority == ANDROID_LOG_DEFAULT) {
655     minimum_priority = ANDROID_LOG_INFO;
656   }
657   return prio >= minimum_priority;
658 }
659 
__android_log_is_loggable_len(int prio,const char *,size_t,int def)660 int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
661   return __android_log_is_loggable(prio, nullptr, def);
662 }
663 
__android_log_is_debuggable()664 int __android_log_is_debuggable() {
665   return 1;
666 }
667 
668 #endif