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