| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 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> |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 18 | #include <pthread.h> |
| 19 | #include <stdlib.h> |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 20 | #include <string.h> |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 21 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ |
| 22 | #include <sys/_system_properties.h> |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 23 | |
| 24 | #include <android/log.h> |
| 25 | |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 26 | static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER; |
| 27 | |
| 28 | static void lock() |
| 29 | { |
| 30 | /* |
| 31 | * If we trigger a signal handler in the middle of locked activity and the |
| 32 | * signal handler logs a message, we could get into a deadlock state. |
| 33 | */ |
| 34 | pthread_mutex_lock(&lock_loggable); |
| 35 | } |
| 36 | |
| 37 | static void unlock() |
| 38 | { |
| 39 | pthread_mutex_unlock(&lock_loggable); |
| 40 | } |
| 41 | |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 42 | struct cache { |
| 43 | const prop_info *pinfo; |
| 44 | uint32_t serial; |
| 45 | char c; |
| 46 | }; |
| 47 | |
| Mark Salyzyn | 233e475 | 2015-12-04 10:59:45 -0800 | [diff] [blame^] | 48 | #define BOOLEAN_TRUE 0xFF |
| 49 | #define BOOLEAN_FALSE 0xFE |
| 50 | |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 51 | static void refresh_cache(struct cache *cache, const char *key) |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 52 | { |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 53 | uint32_t serial; |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 54 | char buf[PROP_VALUE_MAX]; |
| 55 | |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 56 | if (!cache->pinfo) { |
| 57 | cache->pinfo = __system_property_find(key); |
| 58 | if (!cache->pinfo) { |
| 59 | return; |
| 60 | } |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 61 | } |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 62 | serial = __system_property_serial(cache->pinfo); |
| 63 | if (serial == cache->serial) { |
| 64 | return; |
| 65 | } |
| 66 | cache->serial = serial; |
| 67 | __system_property_read(cache->pinfo, 0, buf); |
| Mark Salyzyn | 233e475 | 2015-12-04 10:59:45 -0800 | [diff] [blame^] | 68 | switch(buf[0]) { |
| 69 | case 't': case 'T': |
| 70 | cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE; |
| 71 | break; |
| 72 | case 'f': case 'F': |
| 73 | cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE; |
| 74 | break; |
| 75 | default: |
| 76 | cache->c = buf[0]; |
| 77 | } |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 78 | } |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 79 | |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 80 | static int __android_log_level(const char *tag, int default_prio) |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 81 | { |
| 82 | /* sizeof() is used on this array below */ |
| 83 | static const char log_namespace[] = "persist.log.tag."; |
| 84 | static const size_t base_offset = 8; /* skip "persist." */ |
| 85 | /* calculate the size of our key temporary buffer */ |
| 86 | const size_t taglen = (tag && *tag) ? strlen(tag) : 0; |
| 87 | /* sizeof(log_namespace) = strlen(log_namespace) + 1 */ |
| 88 | char key[sizeof(log_namespace) + taglen]; |
| 89 | char *kp; |
| 90 | size_t i; |
| 91 | char c = 0; |
| 92 | /* |
| 93 | * Single layer cache of four properties. Priorities are: |
| 94 | * log.tag.<tag> |
| 95 | * persist.log.tag.<tag> |
| 96 | * log.tag |
| 97 | * persist.log.tag |
| 98 | * Where the missing tag matches all tags and becomes the |
| 99 | * system global default. We do not support ro.log.tag* . |
| 100 | */ |
| 101 | static char *last_tag; |
| 102 | static uint32_t global_serial; |
| 103 | uint32_t current_global_serial; |
| 104 | static struct cache tag_cache[2] = { |
| 105 | { NULL, -1, 0 }, |
| 106 | { NULL, -1, 0 } |
| 107 | }; |
| 108 | static struct cache global_cache[2] = { |
| 109 | { NULL, -1, 0 }, |
| 110 | { NULL, -1, 0 } |
| 111 | }; |
| 112 | |
| 113 | strcpy(key, log_namespace); |
| 114 | |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 115 | lock(); |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 116 | |
| 117 | current_global_serial = __system_property_area_serial(); |
| 118 | |
| 119 | if (taglen) { |
| 120 | uint32_t current_local_serial = current_global_serial; |
| 121 | |
| Mark Salyzyn | 0cda076 | 2015-10-02 10:00:38 -0700 | [diff] [blame] | 122 | if (!last_tag || (last_tag[0] != tag[0]) || strcmp(last_tag + 1, tag + 1)) { |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 123 | /* invalidate log.tag.<tag> cache */ |
| 124 | for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { |
| 125 | tag_cache[i].pinfo = NULL; |
| 126 | tag_cache[i].serial = -1; |
| 127 | tag_cache[i].c = '\0'; |
| 128 | } |
| 129 | free(last_tag); |
| 130 | last_tag = NULL; |
| 131 | current_global_serial = -1; |
| 132 | } |
| 133 | if (!last_tag) { |
| 134 | last_tag = strdup(tag); |
| 135 | } |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 136 | strcpy(key + sizeof(log_namespace) - 1, tag); |
| 137 | |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 138 | kp = key; |
| 139 | for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { |
| 140 | if (current_local_serial != global_serial) { |
| 141 | refresh_cache(&tag_cache[i], kp); |
| 142 | } |
| 143 | |
| 144 | if (tag_cache[i].c) { |
| 145 | c = tag_cache[i].c; |
| 146 | break; |
| 147 | } |
| 148 | |
| 149 | kp = key + base_offset; |
| Mark Salyzyn | d4b2a74 | 2014-10-08 15:58:40 -0700 | [diff] [blame] | 150 | } |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 151 | } |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 152 | |
| 153 | switch (toupper(c)) { /* if invalid, resort to global */ |
| 154 | case 'V': |
| 155 | case 'D': |
| 156 | case 'I': |
| 157 | case 'W': |
| 158 | case 'E': |
| 159 | case 'F': /* Not officially supported */ |
| 160 | case 'A': |
| 161 | case 'S': |
| Mark Salyzyn | 233e475 | 2015-12-04 10:59:45 -0800 | [diff] [blame^] | 162 | case BOOLEAN_FALSE: /* Not officially supported */ |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 163 | break; |
| 164 | default: |
| 165 | /* clear '.' after log.tag */ |
| 166 | key[sizeof(log_namespace) - 2] = '\0'; |
| 167 | |
| 168 | kp = key; |
| 169 | for(i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { |
| 170 | if (current_global_serial != global_serial) { |
| 171 | refresh_cache(&global_cache[i], kp); |
| 172 | } |
| 173 | |
| 174 | if (global_cache[i].c) { |
| 175 | c = global_cache[i].c; |
| 176 | break; |
| 177 | } |
| 178 | |
| 179 | kp = key + base_offset; |
| 180 | } |
| 181 | break; |
| 182 | } |
| 183 | |
| 184 | global_serial = current_global_serial; |
| 185 | |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 186 | unlock(); |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 187 | |
| 188 | switch (toupper(c)) { |
| 189 | case 'V': return ANDROID_LOG_VERBOSE; |
| 190 | case 'D': return ANDROID_LOG_DEBUG; |
| 191 | case 'I': return ANDROID_LOG_INFO; |
| 192 | case 'W': return ANDROID_LOG_WARN; |
| 193 | case 'E': return ANDROID_LOG_ERROR; |
| 194 | case 'F': /* FALLTHRU */ /* Not officially supported */ |
| 195 | case 'A': return ANDROID_LOG_FATAL; |
| Mark Salyzyn | 233e475 | 2015-12-04 10:59:45 -0800 | [diff] [blame^] | 196 | case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */ |
| Mark Salyzyn | 500cd1c | 2015-03-12 15:46:29 -0700 | [diff] [blame] | 197 | case 'S': return -1; /* ANDROID_LOG_SUPPRESS */ |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 198 | } |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 199 | return default_prio; |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 200 | } |
| 201 | |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 202 | int __android_log_is_loggable(int prio, const char *tag, int default_prio) |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 203 | { |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 204 | int logLevel = __android_log_level(tag, default_prio); |
| Mark Salyzyn | 655b949 | 2014-10-02 11:12:28 -0700 | [diff] [blame] | 205 | return logLevel >= 0 && prio >= logLevel; |
| 206 | } |
| Mark Salyzyn | 2cdfd8e | 2015-09-08 08:32:01 -0700 | [diff] [blame] | 207 | |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 208 | /* |
| 209 | * Timestamp state generally remains constant, since a change is |
| 210 | * rare, we can accept a trylock failure gracefully. Use a separate |
| 211 | * lock from is_loggable to keep contention down b/25563384. |
| 212 | */ |
| Mark Salyzyn | 11a3e70 | 2015-12-01 15:57:25 -0800 | [diff] [blame] | 213 | static pthread_mutex_t lock_clockid = PTHREAD_MUTEX_INITIALIZER; |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 214 | |
| Mark Salyzyn | 11a3e70 | 2015-12-01 15:57:25 -0800 | [diff] [blame] | 215 | clockid_t android_log_clockid() |
| Mark Salyzyn | 2cdfd8e | 2015-09-08 08:32:01 -0700 | [diff] [blame] | 216 | { |
| 217 | static struct cache r_time_cache = { NULL, -1, 0 }; |
| 218 | static struct cache p_time_cache = { NULL, -1, 0 }; |
| Mark Salyzyn | 11a3e70 | 2015-12-01 15:57:25 -0800 | [diff] [blame] | 219 | char c; |
| Mark Salyzyn | 2cdfd8e | 2015-09-08 08:32:01 -0700 | [diff] [blame] | 220 | |
| Mark Salyzyn | 11a3e70 | 2015-12-01 15:57:25 -0800 | [diff] [blame] | 221 | if (pthread_mutex_trylock(&lock_clockid)) { |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 222 | /* We are willing to accept some race in this context */ |
| Mark Salyzyn | 11a3e70 | 2015-12-01 15:57:25 -0800 | [diff] [blame] | 223 | if (!(c = p_time_cache.c)) { |
| 224 | c = r_time_cache.c; |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 225 | } |
| 226 | } else { |
| 227 | static uint32_t serial; |
| 228 | uint32_t current_serial = __system_property_area_serial(); |
| 229 | if (current_serial != serial) { |
| 230 | refresh_cache(&r_time_cache, "ro.logd.timestamp"); |
| 231 | refresh_cache(&p_time_cache, "persist.logd.timestamp"); |
| 232 | serial = current_serial; |
| 233 | } |
| Mark Salyzyn | 11a3e70 | 2015-12-01 15:57:25 -0800 | [diff] [blame] | 234 | if (!(c = p_time_cache.c)) { |
| 235 | c = r_time_cache.c; |
| Mark Salyzyn | 4c68f3f | 2015-11-06 12:26:52 -0800 | [diff] [blame] | 236 | } |
| Mark Salyzyn | 2cdfd8e | 2015-09-08 08:32:01 -0700 | [diff] [blame] | 237 | |
| Mark Salyzyn | 11a3e70 | 2015-12-01 15:57:25 -0800 | [diff] [blame] | 238 | pthread_mutex_unlock(&lock_clockid); |
| Mark Salyzyn | 2cdfd8e | 2015-09-08 08:32:01 -0700 | [diff] [blame] | 239 | } |
| Mark Salyzyn | 2cdfd8e | 2015-09-08 08:32:01 -0700 | [diff] [blame] | 240 | |
| Mark Salyzyn | 11a3e70 | 2015-12-01 15:57:25 -0800 | [diff] [blame] | 241 | return (tolower(c) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME; |
| Mark Salyzyn | 2cdfd8e | 2015-09-08 08:32:01 -0700 | [diff] [blame] | 242 | } |
| Mark Salyzyn | 233e475 | 2015-12-04 10:59:45 -0800 | [diff] [blame^] | 243 | |
| 244 | /* |
| 245 | * security state generally remains constant, since a change is |
| 246 | * rare, we can accept a trylock failure gracefully. |
| 247 | */ |
| 248 | static pthread_mutex_t lock_security = PTHREAD_MUTEX_INITIALIZER; |
| 249 | |
| 250 | int __android_log_security() |
| 251 | { |
| 252 | static struct cache r_do_cache = { NULL, -1, BOOLEAN_FALSE }; |
| 253 | static struct cache p_security_cache = { NULL, -1, BOOLEAN_FALSE }; |
| 254 | int retval; |
| 255 | |
| 256 | if (pthread_mutex_trylock(&lock_security)) { |
| 257 | /* We are willing to accept some race in this context */ |
| 258 | retval = (r_do_cache.c != BOOLEAN_FALSE) && r_do_cache.c && |
| 259 | (p_security_cache.c == BOOLEAN_TRUE); |
| 260 | } else { |
| 261 | static uint32_t serial; |
| 262 | uint32_t current_serial = __system_property_area_serial(); |
| 263 | if (current_serial != serial) { |
| 264 | refresh_cache(&r_do_cache, "ro.device_owner"); |
| 265 | refresh_cache(&p_security_cache, "persist.logd.security"); |
| 266 | serial = current_serial; |
| 267 | } |
| 268 | retval = (r_do_cache.c != BOOLEAN_FALSE) && r_do_cache.c && |
| 269 | (p_security_cache.c == BOOLEAN_TRUE); |
| 270 | |
| 271 | pthread_mutex_unlock(&lock_security); |
| 272 | } |
| 273 | |
| 274 | return retval; |
| 275 | } |