diff --git a/src/util/os_misc.c b/src/util/os_misc.c index e5a780b4035..7eb6ba48a7e 100644 --- a/src/util/os_misc.c +++ b/src/util/os_misc.c @@ -56,6 +56,7 @@ # define LOG_TAG "MESA" # include # include +# include #elif DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD # include #elif DETECT_OS_OPENBSD || DETECT_OS_FREEBSD @@ -121,16 +122,100 @@ os_log_message(const char *message) #endif } +#if DETECT_OS_ANDROID +# include +# include "hash_table.h" +# include "ralloc.h" +# include "simple_mtx.h" + +static struct hash_table *options_tbl; +static simple_mtx_t options_tbl_lock = _SIMPLE_MTX_INITIALIZER_NP; + +static void +options_tbl_fini(void) +{ + _mesa_hash_table_destroy(options_tbl, NULL); +} + +/** + * Get an option value from android's property system, as a fallback to + * getenv() (which is generally less useful on android due to processes + * typically being forked from the zygote. + * + * The option name used for getenv is translated into a property name + * by: + * + * 1) convert to lowercase + * 2) replace '_' with '.' + * 3) if necessary, prepend "mesa." + * + * For example: + * - MESA_EXTENSION_OVERRIDE -> mesa.extension.override + * - GALLIUM_HUD -> mesa.gallium.hud + * + * Note that we use a hashtable for two purposes: + * 1) Avoid re-translating the option name on subsequent lookups + * 2) Avoid leaking memory. Because property_get() returns the + * property value into a user allocated buffer, we cannot return + * that directly to the caller, so we need to strdup(). With the + * hashtable, subsquent lookups can return the existing string. + */ +static const char * +os_get_android_option(const char *name) +{ + if (!options_tbl) { + options_tbl = _mesa_hash_table_create(NULL, _mesa_hash_string, + _mesa_key_string_equal); + atexit(options_tbl_fini); + } + + struct hash_entry *entry = _mesa_hash_table_search(options_tbl, name); + if (entry) { + return entry->data; + } + + char value[PROPERTY_VALUE_MAX]; + char key[PROPERTY_KEY_MAX]; + char *p = key, *end = key + PROPERTY_KEY_MAX; + /* add "mesa." prefix if necessary: */ + if (strstr(name, "MESA_") != name) + p += strlcpy(p, "mesa.", end - p); + p += strlcpy(p, name, end - p); + for (int i = 0; key[i]; i++) { + if (key[i] == '_') { + key[i] = '.'; + } else { + key[i] = tolower(key[i]); + } + } + + const char *opt = NULL; + int len = property_get(key, value, NULL); + if (len > 1) { + opt = ralloc_strdup(options_tbl, value); + } + + _mesa_hash_table_insert(options_tbl, name, value); + + return opt; +} +#endif + #if !defined(EMBEDDED_DEVICE) const char * os_get_option(const char *name) { - return getenv(name); + const char *opt = getenv(name); +#if DETECT_OS_ANDROID + if (!opt) { + opt = os_get_android_option(name); + } +#endif + return opt; } #endif /* !EMBEDDED_DEVICE */ - /** * Return the size of the total physical memory. * \param size returns the size of the total physical memory