static inline unsigned char do_cache2(struct cache2 *self) { uint32_t current_serial; int change_detected; unsigned char c; 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) || check_cache(&self->cache_ro); current_serial = __system_property_area_serial(); if (current_serial != self->serial) { change_detected = 1; } if (change_detected) { refresh_cache(&self->cache_persist, self->key_persist); refresh_cache(&self->cache_ro, self->key_ro); self->serial = current_serial; } c = self->evaluate(self); pthread_mutex_unlock(&self->lock); return c; }
LIBLOG_ABI_PRIVATE int __android_log_is_debuggable() { static uint32_t serial; 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_char temp_cache = { { NULL, -1 }, '\0' }; refresh_cache(&temp_cache, key); ret = temp_cache.c == '1'; } else { int change_detected = check_cache(&tag_cache.cache); uint32_t current_serial = __system_property_area_serial(); if (current_serial != serial) { change_detected = 1; } if (change_detected) { refresh_cache(&tag_cache, key); serial = current_serial; } ret = tag_cache.c == '1'; unlock(); } return ret; }
char android_log_timestamp() { static struct cache r_time_cache = { NULL, -1, 0 }; static struct cache p_time_cache = { NULL, -1, 0 }; char retval; if (pthread_mutex_trylock(&lock_timestamp)) { /* We are willing to accept some race in this context */ if (!(retval = p_time_cache.c)) { retval = r_time_cache.c; } } else { static uint32_t serial; uint32_t current_serial = __system_property_area_serial(); if (current_serial != serial) { refresh_cache(&r_time_cache, "ro.logd.timestamp"); refresh_cache(&p_time_cache, "persist.logd.timestamp"); serial = current_serial; } if (!(retval = p_time_cache.c)) { retval = r_time_cache.c; } pthread_mutex_unlock(&lock_timestamp); } return tolower(retval ?: 'r'); }
static int __android_log_level(const char *tag, int default_prio) { /* sizeof() is used on this array below */ static const char log_namespace[] = "persist.log.tag."; static const size_t base_offset = 8; /* skip "persist." */ /* calculate the size of our key temporary buffer */ const size_t taglen = (tag && *tag) ? strlen(tag) : 0; /* sizeof(log_namespace) = strlen(log_namespace) + 1 */ char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */ char *kp; size_t i; char c = 0; /* * Single layer cache of four properties. Priorities are: * log.tag.<tag> * persist.log.tag.<tag> * log.tag * persist.log.tag * Where the missing tag matches all tags and becomes the * system global default. We do not support ro.log.tag* . */ static char last_tag[PROP_NAME_MAX]; 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]; int change_detected; int global_change_detected; int not_locked; strcpy(key, log_namespace); global_change_detected = change_detected = not_locked = lock(); if (!not_locked) { /* * 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])) { change_detected = 1; } } for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { if (check_cache(&global_cache[i])) { global_change_detected = 1; } } current_global_serial = __system_property_area_serial(); if (current_global_serial != global_serial) { change_detected = 1; global_change_detected = 1; } } if (taglen) { int local_change_detected = change_detected; if (!not_locked) { if (!last_tag[0] || (last_tag[0] != tag[0]) || strncmp(last_tag + 1, tag + 1, sizeof(last_tag) - 1)) { /* 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].c = '\0'; } last_tag[0] = '\0'; local_change_detected = 1; } if (!last_tag[0]) { strncpy(last_tag, tag, sizeof(last_tag)); } } strcpy(key + sizeof(log_namespace) - 1, tag); kp = key; for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { struct cache *cache = &tag_cache[i]; struct cache temp_cache; if (not_locked) { temp_cache.pinfo = NULL; temp_cache.c = '\0'; cache = &temp_cache; } if (local_change_detected) { refresh_cache(cache, kp); } if (cache->c) { c = cache->c; break; } kp = key + base_offset; } } switch (toupper(c)) { /* if invalid, resort to global */ case 'V': case 'D': case 'I': case 'W': case 'E': case 'F': /* Not officially supported */ case 'A': case 'S': case BOOLEAN_FALSE: /* Not officially supported */ break; default: /* clear '.' after log.tag */ key[sizeof(log_namespace) - 2] = '\0'; kp = key; for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { struct cache *cache = &global_cache[i]; struct cache temp_cache; if (not_locked) { temp_cache = *cache; if (temp_cache.pinfo != cache->pinfo) { /* check atomic */ temp_cache.pinfo = NULL; temp_cache.c = '\0'; } cache = &temp_cache; } if (global_change_detected) { refresh_cache(cache, kp); } if (cache->c) { c = cache->c; break; } kp = key + base_offset; } break; } if (!not_locked) { global_serial = current_global_serial; unlock(); } switch (toupper(c)) { case 'V': return ANDROID_LOG_VERBOSE; case 'D': return ANDROID_LOG_DEBUG; case 'I': return ANDROID_LOG_INFO; case 'W': return ANDROID_LOG_WARN; case 'E': return ANDROID_LOG_ERROR; case 'F': /* FALLTHRU */ /* Not officially supported */ case 'A': return ANDROID_LOG_FATAL; case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */ case 'S': return -1; /* ANDROID_LOG_SUPPRESS */ } return default_prio; }
static int __android_log_level(const char *tag, int flag) { /* sizeof() is used on this array below */ static const char log_namespace[] = "persist.log.tag."; static const size_t base_offset = 8; /* skip "persist." */ /* calculate the size of our key temporary buffer */ const size_t taglen = (tag && *tag) ? strlen(tag) : 0; /* sizeof(log_namespace) = strlen(log_namespace) + 1 */ char key[sizeof(log_namespace) + taglen]; char *kp; size_t i; char c = 0; /* * Single layer cache of four properties. Priorities are: * log.tag.<tag> * persist.log.tag.<tag> * log.tag * persist.log.tag * Where the missing tag matches all tags and becomes the * system global default. We do not support ro.log.tag* . */ static char *last_tag; static uint32_t global_serial; uint32_t current_global_serial; static struct cache tag_cache[2] = { { NULL, -1, 0 }, { NULL, -1, 0 } }; static struct cache global_cache[2] = { { NULL, -1, 0 }, { NULL, -1, 0 } }; sigset_t sigflags; strcpy(key, log_namespace); lock((flag & ANDROID_LOGGABLE_FLAG_NOT_WITHIN_SIGNAL) ? NULL : &sigflags); current_global_serial = __system_property_area_serial(); if (taglen) { uint32_t current_local_serial = current_global_serial; if (!last_tag || (last_tag[0] != tag[0]) || strcmp(last_tag + 1, tag + 1)) { /* 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].serial = -1; tag_cache[i].c = '\0'; } free(last_tag); last_tag = NULL; current_global_serial = -1; } if (!last_tag) { last_tag = strdup(tag); } strcpy(key + sizeof(log_namespace) - 1, tag); kp = key; for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { if (current_local_serial != global_serial) { refresh_cache(&tag_cache[i], kp); } if (tag_cache[i].c) { c = tag_cache[i].c; break; } kp = key + base_offset; } } switch (toupper(c)) { /* if invalid, resort to global */ case 'V': case 'D': case 'I': case 'W': case 'E': case 'F': /* Not officially supported */ case 'A': case 'S': break; default: /* clear '.' after log.tag */ key[sizeof(log_namespace) - 2] = '\0'; kp = key; for(i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { if (current_global_serial != global_serial) { refresh_cache(&global_cache[i], kp); } if (global_cache[i].c) { c = global_cache[i].c; break; } kp = key + base_offset; } break; } global_serial = current_global_serial; unlock((flag & ANDROID_LOGGABLE_FLAG_NOT_WITHIN_SIGNAL) ? NULL : &sigflags); switch (toupper(c)) { case 'V': return ANDROID_LOG_VERBOSE; case 'D': return ANDROID_LOG_DEBUG; case 'I': return ANDROID_LOG_INFO; case 'W': return ANDROID_LOG_WARN; case 'E': return ANDROID_LOG_ERROR; case 'F': /* FALLTHRU */ /* Not officially supported */ case 'A': return ANDROID_LOG_FATAL; case 'S': return -1; /* ANDROID_LOG_SUPPRESS */ } return flag & ANDROID_LOGGABLE_FLAG_DEFAULT_MASK; }