Loading include/private/android_logger.h +15 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ /* Android private interfaces */ #include <stdbool.h> #include <stdint.h> #include <sys/types.h> Loading Loading @@ -132,6 +133,20 @@ int __android_log_security(); /* Device Owner is present */ int __android_log_is_debuggable(); #define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1 #define BOOL_DEFAULT_FALSE 0x0 /* false if property not present */ #define BOOL_DEFAULT_TRUE 0x1 /* true if property not present */ #define BOOL_DEFAULT_FLAG_PERSIST 0x2 /* <key>, persist.<key>, ro.<key> */ #define BOOL_DEFAULT_FLAG_ENG 0x4 /* off for user */ #define BOOL_DEFAULT_FLAG_SVELTE 0x8 /* off for low_ram */ bool __android_logger_property_get_bool(const char *key, int flag); #define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform */ #define LOG_BUFFER_MIN_SIZE (64 * 1024UL) #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL) unsigned long __android_logger_get_buffer_size(log_id_t logId); bool __android_logger_valid_buffer_size(unsigned long value); #if defined(__cplusplus) } #endif Loading liblog/log_is_loggable.c +305 −47 Original line number Diff line number Diff line Loading @@ -16,12 +16,16 @@ #include <ctype.h> #include <pthread.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> #include <unistd.h> #include <android/log.h> #include <log/logger.h> #include <private/android_logger.h> #include "log_portability.h" Loading Loading @@ -49,6 +53,10 @@ static void unlock() struct cache { const prop_info* pinfo; uint32_t serial; }; struct cache_char { struct cache cache; unsigned char c; }; Loading @@ -61,18 +69,18 @@ static int check_cache(struct cache *cache) #define BOOLEAN_TRUE 0xFF #define BOOLEAN_FALSE 0xFE static void refresh_cache(struct cache *cache, const char *key) static void refresh_cache(struct cache_char* cache, const char* key) { char buf[PROP_VALUE_MAX]; if (!cache->pinfo) { cache->pinfo = __system_property_find(key); if (!cache->pinfo) { if (!cache->cache.pinfo) { cache->cache.pinfo = __system_property_find(key); if (!cache->cache.pinfo) { return; } } cache->serial = __system_property_serial(cache->pinfo); __system_property_read(cache->pinfo, 0, buf); cache->cache.serial = __system_property_serial(cache->cache.pinfo); __system_property_read(cache->cache.pinfo, 0, buf); switch(buf[0]) { case 't': case 'T': cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE; Loading @@ -93,7 +101,7 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) /* calculate the size of our key temporary buffer */ const size_t taglen = tag ? len : 0; /* sizeof(log_namespace) = strlen(log_namespace) + 1 */ char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */ char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */ char* kp; size_t i; char c = 0; Loading @@ -110,8 +118,8 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) static uint32_t global_serial; /* some compilers erroneously see uninitialized use. !not_locked */ uint32_t current_global_serial = 0; static struct cache tag_cache[2]; static struct cache global_cache[2]; static struct cache_char tag_cache[2]; static struct cache_char global_cache[2]; int change_detected; int global_change_detected; int not_locked; Loading @@ -125,12 +133,12 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) * check all known serial numbers to changes. */ for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { if (check_cache(&tag_cache[i])) { if (check_cache(&tag_cache[i].cache)) { change_detected = 1; } } for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { if (check_cache(&global_cache[i])) { if (check_cache(&global_cache[i].cache)) { global_change_detected = 1; } } Loading @@ -154,7 +162,7 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) || ((len < sizeof(last_tag)) && last_tag[len])) { /* invalidate log.tag.<tag> cache */ for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { tag_cache[i].pinfo = NULL; tag_cache[i].cache.pinfo = NULL; tag_cache[i].c = '\0'; } last_tag[0] = '\0'; Loading @@ -174,11 +182,11 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) kp = key; for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { struct cache *cache = &tag_cache[i]; struct cache temp_cache; struct cache_char* cache = &tag_cache[i]; struct cache_char temp_cache; if (not_locked) { temp_cache.pinfo = NULL; temp_cache.cache.pinfo = NULL; temp_cache.c = '\0'; cache = &temp_cache; } Loading Loading @@ -212,13 +220,13 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) kp = key; for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { struct cache *cache = &global_cache[i]; struct cache temp_cache; struct cache_char* cache = &global_cache[i]; struct cache_char temp_cache; if (not_locked) { temp_cache = *cache; if (temp_cache.pinfo != cache->pinfo) { /* check atomic */ temp_cache.pinfo = NULL; if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */ temp_cache.cache.pinfo = NULL; temp_cache.c = '\0'; } cache = &temp_cache; Loading Loading @@ -277,18 +285,18 @@ LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, LIBLOG_ABI_PRIVATE int __android_log_is_debuggable() { static uint32_t serial; static struct cache tag_cache; static struct cache_char tag_cache; static const char key[] = "ro.debuggable"; int ret; if (tag_cache.c) { /* ro property does not change after set */ ret = tag_cache.c == '1'; } else if (lock()) { struct cache temp_cache = { NULL, -1, '\0' }; struct cache_char temp_cache = { { NULL, -1 }, '\0' }; refresh_cache(&temp_cache, key); ret = temp_cache.c == '1'; } else { int change_detected = check_cache(&tag_cache); int change_detected = check_cache(&tag_cache.cache); uint32_t current_serial = __system_property_area_serial(); if (current_serial != serial) { change_detected = 1; Loading @@ -310,17 +318,17 @@ LIBLOG_ABI_PRIVATE int __android_log_is_debuggable() * Since a change is rare, we will accept a trylock failure gracefully. * Use a separate lock from is_loggable to keep contention down b/25563384. */ struct cache2 { struct cache2_char { pthread_mutex_t lock; uint32_t serial; const char* key_persist; struct cache cache_persist; struct cache_char cache_persist; const char* key_ro; struct cache cache_ro; unsigned char (*const evaluate)(const struct cache2 *self); struct cache_char cache_ro; unsigned char (*const evaluate)(const struct cache2_char *self); }; static inline unsigned char do_cache2(struct cache2 *self) static inline unsigned char do_cache2_char(struct cache2_char *self) { uint32_t current_serial; int change_detected; Loading @@ -331,8 +339,8 @@ static inline unsigned char do_cache2(struct cache2 *self) return self->evaluate(self); } change_detected = check_cache(&self->cache_persist) || check_cache(&self->cache_ro); change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache); current_serial = __system_property_area_serial(); if (current_serial != self->serial) { change_detected = 1; Loading @@ -349,7 +357,7 @@ static inline unsigned char do_cache2(struct cache2 *self) return c; } static unsigned char evaluate_persist_ro(const struct cache2 *self) static unsigned char evaluate_persist_ro(const struct cache2_char *self) { unsigned char c = self->cache_persist.c; Loading @@ -366,17 +374,17 @@ static unsigned char evaluate_persist_ro(const struct cache2 *self) */ LIBLOG_ABI_PUBLIC clockid_t android_log_clockid() { static struct cache2 clockid = { static struct cache2_char clockid = { PTHREAD_MUTEX_INITIALIZER, 0, "persist.logd.timestamp", { NULL, -1, '\0' }, { { NULL, -1 }, '\0' }, "ro.logd.timestamp", { NULL, -1, '\0' }, { { NULL, -1 }, '\0' }, evaluate_persist_ro }; return (tolower(do_cache2(&clockid)) == 'm') return (tolower(do_cache2_char(&clockid)) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME; } Loading @@ -385,7 +393,7 @@ LIBLOG_ABI_PUBLIC clockid_t android_log_clockid() * Security state generally remains constant, but the DO must be able * to turn off logging should it become spammy after an attack is detected. */ static unsigned char evaluate_security(const struct cache2 *self) static unsigned char evaluate_security(const struct cache2_char *self) { unsigned char c = self->cache_ro.c; Loading @@ -394,15 +402,265 @@ static unsigned char evaluate_security(const struct cache2 *self) LIBLOG_ABI_PUBLIC int __android_log_security() { static struct cache2 security = { static struct cache2_char security = { PTHREAD_MUTEX_INITIALIZER, 0, "persist.logd.security", { NULL, -1, BOOLEAN_FALSE }, { { NULL, -1 }, BOOLEAN_FALSE }, "ro.device_owner", { NULL, -1, BOOLEAN_FALSE }, { { NULL, -1 }, BOOLEAN_FALSE }, evaluate_security }; return do_cache2(&security); return do_cache2_char(&security); } /* * Interface that represents the logd buffer size determination so that others * need not guess our intentions. */ /* Property helper */ static bool check_flag(const char* prop, const char* flag) { const char* cp = strcasestr(prop, flag); if (!cp) { return false; } /* We only will document comma (,) */ static const char sep[] = ",:;|+ \t\f"; if ((cp != prop) && !strchr(sep, cp[-1])) { return false; } cp += strlen(flag); return !*cp || !!strchr(sep, *cp); } /* cache structure */ struct cache_property { struct cache cache; char property[PROP_VALUE_MAX]; }; static void refresh_cache_property(struct cache_property* cache, const char* key) { if (!cache->cache.pinfo) { cache->cache.pinfo = __system_property_find(key); if (!cache->cache.pinfo) { return; } } cache->cache.serial = __system_property_serial(cache->cache.pinfo); __system_property_read(cache->cache.pinfo, 0, cache->property); } /* get boolean with the logger twist that supports eng adjustments */ LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key, int flag) { struct cache_property property = { { NULL, -1 }, { 0 } }; if (flag & BOOL_DEFAULT_FLAG_PERSIST) { char newkey[PROP_NAME_MAX]; snprintf(newkey, sizeof(newkey), "ro.%s", key); refresh_cache_property(&property, newkey); property.cache.pinfo = NULL; property.cache.serial = -1; snprintf(newkey, sizeof(newkey), "persist.%s", key); refresh_cache_property(&property, newkey); property.cache.pinfo = NULL; property.cache.serial = -1; } refresh_cache_property(&property, key); if (check_flag(property.property, "true")) { return true; } if (check_flag(property.property, "false")) { return false; } if (check_flag(property.property, "eng")) { flag |= BOOL_DEFAULT_FLAG_ENG; } /* this is really a "not" flag */ if (check_flag(property.property, "svelte")) { flag |= BOOL_DEFAULT_FLAG_SVELTE; } /* Sanity Check */ if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) { flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE; flag |= BOOL_DEFAULT_TRUE; } if ((flag & BOOL_DEFAULT_FLAG_SVELTE) && __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE)) { return false; } if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) { return false; } return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE; } LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value) { static long pages, pagesize; unsigned long maximum; if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) { return false; } if (!pages) { pages = sysconf(_SC_PHYS_PAGES); } if (pages < 1) { return true; } if (!pagesize) { pagesize = sysconf(_SC_PAGESIZE); if (pagesize <= 1) { pagesize = PAGE_SIZE; } } /* maximum memory impact a somewhat arbitrary ~3% */ pages = (pages + 31) / 32; maximum = pages * pagesize; if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) { return true; } return value <= maximum; } struct cache2_property_size { pthread_mutex_t lock; uint32_t serial; const char* key_persist; struct cache_property cache_persist; const char* key_ro; struct cache_property cache_ro; unsigned long (*const evaluate)(const struct cache2_property_size* self); }; static inline unsigned long do_cache2_property_size(struct cache2_property_size* self) { uint32_t current_serial; int change_detected; unsigned long v; if (pthread_mutex_trylock(&self->lock)) { /* We are willing to accept some race in this context */ return self->evaluate(self); } change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache); current_serial = __system_property_area_serial(); if (current_serial != self->serial) { change_detected = 1; } if (change_detected) { refresh_cache_property(&self->cache_persist, self->key_persist); refresh_cache_property(&self->cache_ro, self->key_ro); self->serial = current_serial; } v = self->evaluate(self); pthread_mutex_unlock(&self->lock); return v; } static unsigned long property_get_size_from_cache(const struct cache_property* cache) { char* cp; unsigned long value = strtoul(cache->property, &cp, 10); switch(*cp) { case 'm': case 'M': value *= 1024; /* FALLTHRU */ case 'k': case 'K': value *= 1024; /* FALLTHRU */ case '\0': break; default: value = 0; } if (!__android_logger_valid_buffer_size(value)) { value = 0; } return value; } static unsigned long evaluate_property_get_size(const struct cache2_property_size* self) { unsigned long size = property_get_size_from_cache(&self->cache_persist); if (size) { return size; } return property_get_size_from_cache(&self->cache_ro); } LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId) { static const char global_tunable[] = "persist.logd.size"; /* Settings App */ static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */ static struct cache2_property_size global = { PTHREAD_MUTEX_INITIALIZER, 0, global_tunable, { { NULL, -1 }, {} }, global_default, { { NULL, -1 }, {} }, evaluate_property_get_size }; char key_persist[PROP_NAME_MAX]; char key_ro[PROP_NAME_MAX]; struct cache2_property_size local = { PTHREAD_MUTEX_INITIALIZER, 0, key_persist, { { NULL, -1 }, {} }, key_ro, { { NULL, -1 }, {} }, evaluate_property_get_size }; unsigned long property_size, default_size; default_size = do_cache2_property_size(&global); if (!default_size) { default_size = __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE) ? LOG_BUFFER_MIN_SIZE /* 64K */ : LOG_BUFFER_SIZE; /* 256K */ } snprintf(key_persist, sizeof(key_persist), "%s.%s", global_tunable, android_log_id_to_name(logId)); snprintf(key_ro, sizeof(key_ro), "%s.%s", global_default, android_log_id_to_name(logId)); property_size = do_cache2_property_size(&local); if (!property_size) { property_size = default_size; } if (!property_size) { property_size = LOG_BUFFER_SIZE; } return property_size; } Loading
include/private/android_logger.h +15 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ /* Android private interfaces */ #include <stdbool.h> #include <stdint.h> #include <sys/types.h> Loading Loading @@ -132,6 +133,20 @@ int __android_log_security(); /* Device Owner is present */ int __android_log_is_debuggable(); #define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1 #define BOOL_DEFAULT_FALSE 0x0 /* false if property not present */ #define BOOL_DEFAULT_TRUE 0x1 /* true if property not present */ #define BOOL_DEFAULT_FLAG_PERSIST 0x2 /* <key>, persist.<key>, ro.<key> */ #define BOOL_DEFAULT_FLAG_ENG 0x4 /* off for user */ #define BOOL_DEFAULT_FLAG_SVELTE 0x8 /* off for low_ram */ bool __android_logger_property_get_bool(const char *key, int flag); #define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform */ #define LOG_BUFFER_MIN_SIZE (64 * 1024UL) #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL) unsigned long __android_logger_get_buffer_size(log_id_t logId); bool __android_logger_valid_buffer_size(unsigned long value); #if defined(__cplusplus) } #endif Loading
liblog/log_is_loggable.c +305 −47 Original line number Diff line number Diff line Loading @@ -16,12 +16,16 @@ #include <ctype.h> #include <pthread.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> #include <unistd.h> #include <android/log.h> #include <log/logger.h> #include <private/android_logger.h> #include "log_portability.h" Loading Loading @@ -49,6 +53,10 @@ static void unlock() struct cache { const prop_info* pinfo; uint32_t serial; }; struct cache_char { struct cache cache; unsigned char c; }; Loading @@ -61,18 +69,18 @@ static int check_cache(struct cache *cache) #define BOOLEAN_TRUE 0xFF #define BOOLEAN_FALSE 0xFE static void refresh_cache(struct cache *cache, const char *key) static void refresh_cache(struct cache_char* cache, const char* key) { char buf[PROP_VALUE_MAX]; if (!cache->pinfo) { cache->pinfo = __system_property_find(key); if (!cache->pinfo) { if (!cache->cache.pinfo) { cache->cache.pinfo = __system_property_find(key); if (!cache->cache.pinfo) { return; } } cache->serial = __system_property_serial(cache->pinfo); __system_property_read(cache->pinfo, 0, buf); cache->cache.serial = __system_property_serial(cache->cache.pinfo); __system_property_read(cache->cache.pinfo, 0, buf); switch(buf[0]) { case 't': case 'T': cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE; Loading @@ -93,7 +101,7 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) /* calculate the size of our key temporary buffer */ const size_t taglen = tag ? len : 0; /* sizeof(log_namespace) = strlen(log_namespace) + 1 */ char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */ char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */ char* kp; size_t i; char c = 0; Loading @@ -110,8 +118,8 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) static uint32_t global_serial; /* some compilers erroneously see uninitialized use. !not_locked */ uint32_t current_global_serial = 0; static struct cache tag_cache[2]; static struct cache global_cache[2]; static struct cache_char tag_cache[2]; static struct cache_char global_cache[2]; int change_detected; int global_change_detected; int not_locked; Loading @@ -125,12 +133,12 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) * check all known serial numbers to changes. */ for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { if (check_cache(&tag_cache[i])) { if (check_cache(&tag_cache[i].cache)) { change_detected = 1; } } for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { if (check_cache(&global_cache[i])) { if (check_cache(&global_cache[i].cache)) { global_change_detected = 1; } } Loading @@ -154,7 +162,7 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) || ((len < sizeof(last_tag)) && last_tag[len])) { /* invalidate log.tag.<tag> cache */ for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { tag_cache[i].pinfo = NULL; tag_cache[i].cache.pinfo = NULL; tag_cache[i].c = '\0'; } last_tag[0] = '\0'; Loading @@ -174,11 +182,11 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) kp = key; for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { struct cache *cache = &tag_cache[i]; struct cache temp_cache; struct cache_char* cache = &tag_cache[i]; struct cache_char temp_cache; if (not_locked) { temp_cache.pinfo = NULL; temp_cache.cache.pinfo = NULL; temp_cache.c = '\0'; cache = &temp_cache; } Loading Loading @@ -212,13 +220,13 @@ static int __android_log_level(const char *tag, size_t len, int default_prio) kp = key; for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { struct cache *cache = &global_cache[i]; struct cache temp_cache; struct cache_char* cache = &global_cache[i]; struct cache_char temp_cache; if (not_locked) { temp_cache = *cache; if (temp_cache.pinfo != cache->pinfo) { /* check atomic */ temp_cache.pinfo = NULL; if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */ temp_cache.cache.pinfo = NULL; temp_cache.c = '\0'; } cache = &temp_cache; Loading Loading @@ -277,18 +285,18 @@ LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, LIBLOG_ABI_PRIVATE int __android_log_is_debuggable() { static uint32_t serial; static struct cache tag_cache; static struct cache_char tag_cache; static const char key[] = "ro.debuggable"; int ret; if (tag_cache.c) { /* ro property does not change after set */ ret = tag_cache.c == '1'; } else if (lock()) { struct cache temp_cache = { NULL, -1, '\0' }; struct cache_char temp_cache = { { NULL, -1 }, '\0' }; refresh_cache(&temp_cache, key); ret = temp_cache.c == '1'; } else { int change_detected = check_cache(&tag_cache); int change_detected = check_cache(&tag_cache.cache); uint32_t current_serial = __system_property_area_serial(); if (current_serial != serial) { change_detected = 1; Loading @@ -310,17 +318,17 @@ LIBLOG_ABI_PRIVATE int __android_log_is_debuggable() * Since a change is rare, we will accept a trylock failure gracefully. * Use a separate lock from is_loggable to keep contention down b/25563384. */ struct cache2 { struct cache2_char { pthread_mutex_t lock; uint32_t serial; const char* key_persist; struct cache cache_persist; struct cache_char cache_persist; const char* key_ro; struct cache cache_ro; unsigned char (*const evaluate)(const struct cache2 *self); struct cache_char cache_ro; unsigned char (*const evaluate)(const struct cache2_char *self); }; static inline unsigned char do_cache2(struct cache2 *self) static inline unsigned char do_cache2_char(struct cache2_char *self) { uint32_t current_serial; int change_detected; Loading @@ -331,8 +339,8 @@ static inline unsigned char do_cache2(struct cache2 *self) return self->evaluate(self); } change_detected = check_cache(&self->cache_persist) || check_cache(&self->cache_ro); change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache); current_serial = __system_property_area_serial(); if (current_serial != self->serial) { change_detected = 1; Loading @@ -349,7 +357,7 @@ static inline unsigned char do_cache2(struct cache2 *self) return c; } static unsigned char evaluate_persist_ro(const struct cache2 *self) static unsigned char evaluate_persist_ro(const struct cache2_char *self) { unsigned char c = self->cache_persist.c; Loading @@ -366,17 +374,17 @@ static unsigned char evaluate_persist_ro(const struct cache2 *self) */ LIBLOG_ABI_PUBLIC clockid_t android_log_clockid() { static struct cache2 clockid = { static struct cache2_char clockid = { PTHREAD_MUTEX_INITIALIZER, 0, "persist.logd.timestamp", { NULL, -1, '\0' }, { { NULL, -1 }, '\0' }, "ro.logd.timestamp", { NULL, -1, '\0' }, { { NULL, -1 }, '\0' }, evaluate_persist_ro }; return (tolower(do_cache2(&clockid)) == 'm') return (tolower(do_cache2_char(&clockid)) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME; } Loading @@ -385,7 +393,7 @@ LIBLOG_ABI_PUBLIC clockid_t android_log_clockid() * Security state generally remains constant, but the DO must be able * to turn off logging should it become spammy after an attack is detected. */ static unsigned char evaluate_security(const struct cache2 *self) static unsigned char evaluate_security(const struct cache2_char *self) { unsigned char c = self->cache_ro.c; Loading @@ -394,15 +402,265 @@ static unsigned char evaluate_security(const struct cache2 *self) LIBLOG_ABI_PUBLIC int __android_log_security() { static struct cache2 security = { static struct cache2_char security = { PTHREAD_MUTEX_INITIALIZER, 0, "persist.logd.security", { NULL, -1, BOOLEAN_FALSE }, { { NULL, -1 }, BOOLEAN_FALSE }, "ro.device_owner", { NULL, -1, BOOLEAN_FALSE }, { { NULL, -1 }, BOOLEAN_FALSE }, evaluate_security }; return do_cache2(&security); return do_cache2_char(&security); } /* * Interface that represents the logd buffer size determination so that others * need not guess our intentions. */ /* Property helper */ static bool check_flag(const char* prop, const char* flag) { const char* cp = strcasestr(prop, flag); if (!cp) { return false; } /* We only will document comma (,) */ static const char sep[] = ",:;|+ \t\f"; if ((cp != prop) && !strchr(sep, cp[-1])) { return false; } cp += strlen(flag); return !*cp || !!strchr(sep, *cp); } /* cache structure */ struct cache_property { struct cache cache; char property[PROP_VALUE_MAX]; }; static void refresh_cache_property(struct cache_property* cache, const char* key) { if (!cache->cache.pinfo) { cache->cache.pinfo = __system_property_find(key); if (!cache->cache.pinfo) { return; } } cache->cache.serial = __system_property_serial(cache->cache.pinfo); __system_property_read(cache->cache.pinfo, 0, cache->property); } /* get boolean with the logger twist that supports eng adjustments */ LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key, int flag) { struct cache_property property = { { NULL, -1 }, { 0 } }; if (flag & BOOL_DEFAULT_FLAG_PERSIST) { char newkey[PROP_NAME_MAX]; snprintf(newkey, sizeof(newkey), "ro.%s", key); refresh_cache_property(&property, newkey); property.cache.pinfo = NULL; property.cache.serial = -1; snprintf(newkey, sizeof(newkey), "persist.%s", key); refresh_cache_property(&property, newkey); property.cache.pinfo = NULL; property.cache.serial = -1; } refresh_cache_property(&property, key); if (check_flag(property.property, "true")) { return true; } if (check_flag(property.property, "false")) { return false; } if (check_flag(property.property, "eng")) { flag |= BOOL_DEFAULT_FLAG_ENG; } /* this is really a "not" flag */ if (check_flag(property.property, "svelte")) { flag |= BOOL_DEFAULT_FLAG_SVELTE; } /* Sanity Check */ if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) { flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE; flag |= BOOL_DEFAULT_TRUE; } if ((flag & BOOL_DEFAULT_FLAG_SVELTE) && __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE)) { return false; } if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) { return false; } return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE; } LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value) { static long pages, pagesize; unsigned long maximum; if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) { return false; } if (!pages) { pages = sysconf(_SC_PHYS_PAGES); } if (pages < 1) { return true; } if (!pagesize) { pagesize = sysconf(_SC_PAGESIZE); if (pagesize <= 1) { pagesize = PAGE_SIZE; } } /* maximum memory impact a somewhat arbitrary ~3% */ pages = (pages + 31) / 32; maximum = pages * pagesize; if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) { return true; } return value <= maximum; } struct cache2_property_size { pthread_mutex_t lock; uint32_t serial; const char* key_persist; struct cache_property cache_persist; const char* key_ro; struct cache_property cache_ro; unsigned long (*const evaluate)(const struct cache2_property_size* self); }; static inline unsigned long do_cache2_property_size(struct cache2_property_size* self) { uint32_t current_serial; int change_detected; unsigned long v; if (pthread_mutex_trylock(&self->lock)) { /* We are willing to accept some race in this context */ return self->evaluate(self); } change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache); current_serial = __system_property_area_serial(); if (current_serial != self->serial) { change_detected = 1; } if (change_detected) { refresh_cache_property(&self->cache_persist, self->key_persist); refresh_cache_property(&self->cache_ro, self->key_ro); self->serial = current_serial; } v = self->evaluate(self); pthread_mutex_unlock(&self->lock); return v; } static unsigned long property_get_size_from_cache(const struct cache_property* cache) { char* cp; unsigned long value = strtoul(cache->property, &cp, 10); switch(*cp) { case 'm': case 'M': value *= 1024; /* FALLTHRU */ case 'k': case 'K': value *= 1024; /* FALLTHRU */ case '\0': break; default: value = 0; } if (!__android_logger_valid_buffer_size(value)) { value = 0; } return value; } static unsigned long evaluate_property_get_size(const struct cache2_property_size* self) { unsigned long size = property_get_size_from_cache(&self->cache_persist); if (size) { return size; } return property_get_size_from_cache(&self->cache_ro); } LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId) { static const char global_tunable[] = "persist.logd.size"; /* Settings App */ static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */ static struct cache2_property_size global = { PTHREAD_MUTEX_INITIALIZER, 0, global_tunable, { { NULL, -1 }, {} }, global_default, { { NULL, -1 }, {} }, evaluate_property_get_size }; char key_persist[PROP_NAME_MAX]; char key_ro[PROP_NAME_MAX]; struct cache2_property_size local = { PTHREAD_MUTEX_INITIALIZER, 0, key_persist, { { NULL, -1 }, {} }, key_ro, { { NULL, -1 }, {} }, evaluate_property_get_size }; unsigned long property_size, default_size; default_size = do_cache2_property_size(&global); if (!default_size) { default_size = __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE) ? LOG_BUFFER_MIN_SIZE /* 64K */ : LOG_BUFFER_SIZE; /* 256K */ } snprintf(key_persist, sizeof(key_persist), "%s.%s", global_tunable, android_log_id_to_name(logId)); snprintf(key_ro, sizeof(key_ro), "%s.%s", global_default, android_log_id_to_name(logId)); property_size = do_cache2_property_size(&local); if (!property_size) { property_size = default_size; } if (!property_size) { property_size = LOG_BUFFER_SIZE; } return property_size; }