Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88067666 authored by Mark Salyzyn's avatar Mark Salyzyn Committed by android-build-merger
Browse files

Merge "liblog: Add private interfaces for buffer size properties"

am: 094004bf

Change-Id: I81c6ff947b0f0939b41ea59dae153c5584ac9049
parents 95bcd980 094004bf
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@

/* Android private interfaces */

#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>

@@ -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
+305 −47
Original line number Diff line number Diff line
@@ -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"

@@ -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;
};

@@ -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;
@@ -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;
@@ -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;
@@ -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;
            }
        }
@@ -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';
@@ -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;
            }
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;

@@ -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;
}
@@ -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;

@@ -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;
}