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> 18 #include <pthread.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 22 #include <sys/_system_properties.h> 23 24 #include <android/log.h> 25 26 #include "log_portability.h" 27 28 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER; 29 30 static int lock() 31 { 32 /* 33 * If we trigger a signal handler in the middle of locked activity and the 34 * signal handler logs a message, we could get into a deadlock state. 35 */ 36 /* 37 * Any contention, and we can turn around and use the non-cached method 38 * in less time than the system call associated with a mutex to deal with 39 * the contention. 40 */ 41 return pthread_mutex_trylock(&lock_loggable); 42 } 43 44 static void unlock() 45 { 46 pthread_mutex_unlock(&lock_loggable); 47 } 48 49 struct cache { 50 const prop_info *pinfo; 51 uint32_t serial; 52 unsigned char c; 53 }; 54 55 static int check_cache(struct cache *cache) 56 { 57 return cache->pinfo 58 && __system_property_serial(cache->pinfo) != cache->serial; 59 } 60 61 #define BOOLEAN_TRUE 0xFF 62 #define BOOLEAN_FALSE 0xFE 63 64 static void refresh_cache(struct cache *cache, const char *key) 65 { 66 char buf[PROP_VALUE_MAX]; 67 68 if (!cache->pinfo) { 69 cache->pinfo = __system_property_find(key); 70 if (!cache->pinfo) { 71 return; 72 } 73 } 74 cache->serial = __system_property_serial(cache->pinfo); 75 __system_property_read(cache->pinfo, 0, buf); 76 switch(buf[0]) { 77 case 't': case 'T': 78 cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE; 79 break; 80 case 'f': case 'F': 81 cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE; 82 break; 83 default: 84 cache->c = buf[0]; 85 } 86 } 87 88 static int __android_log_level(const char *tag, int default_prio) 89 { 90 /* sizeof() is used on this array below */ 91 static const char log_namespace[] = "persist.log.tag."; 92 static const size_t base_offset = 8; /* skip "persist." */ 93 /* calculate the size of our key temporary buffer */ 94 const size_t taglen = (tag && *tag) ? strlen(tag) : 0; 95 /* sizeof(log_namespace) = strlen(log_namespace) + 1 */ 96 char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */ 97 char *kp; 98 size_t i; 99 char c = 0; 100 /* 101 * Single layer cache of four properties. Priorities are: 102 * log.tag.<tag> 103 * persist.log.tag.<tag> 104 * log.tag 105 * persist.log.tag 106 * Where the missing tag matches all tags and becomes the 107 * system global default. We do not support ro.log.tag* . 108 */ 109 static char last_tag[PROP_NAME_MAX]; 110 static uint32_t global_serial; 111 /* some compilers erroneously see uninitialized use. !not_locked */ 112 uint32_t current_global_serial = 0; 113 static struct cache tag_cache[2]; 114 static struct cache global_cache[2]; 115 int change_detected; 116 int global_change_detected; 117 int not_locked; 118 119 strcpy(key, log_namespace); 120 121 global_change_detected = change_detected = not_locked = lock(); 122 123 if (!not_locked) { 124 /* 125 * check all known serial numbers to changes. 126 */ 127 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { 128 if (check_cache(&tag_cache[i])) { 129 change_detected = 1; 130 } 131 } 132 for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { 133 if (check_cache(&global_cache[i])) { 134 global_change_detected = 1; 135 } 136 } 137 138 current_global_serial = __system_property_area_serial(); 139 if (current_global_serial != global_serial) { 140 change_detected = 1; 141 global_change_detected = 1; 142 } 143 } 144 145 if (taglen) { 146 int local_change_detected = change_detected; 147 if (!not_locked) { 148 if (!last_tag[0] 149 || (last_tag[0] != tag[0]) 150 || strncmp(last_tag + 1, tag + 1, sizeof(last_tag) - 1)) { 151 /* invalidate log.tag.<tag> cache */ 152 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { 153 tag_cache[i].pinfo = NULL; 154 tag_cache[i].c = '\0'; 155 } 156 last_tag[0] = '\0'; 157 local_change_detected = 1; 158 } 159 if (!last_tag[0]) { 160 strncpy(last_tag, tag, sizeof(last_tag)); 161 } 162 } 163 strcpy(key + sizeof(log_namespace) - 1, tag); 164 165 kp = key; 166 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { 167 struct cache *cache = &tag_cache[i]; 168 struct cache temp_cache; 169 170 if (not_locked) { 171 temp_cache.pinfo = NULL; 172 temp_cache.c = '\0'; 173 cache = &temp_cache; 174 } 175 if (local_change_detected) { 176 refresh_cache(cache, kp); 177 } 178 179 if (cache->c) { 180 c = cache->c; 181 break; 182 } 183 184 kp = key + base_offset; 185 } 186 } 187 188 switch (toupper(c)) { /* if invalid, resort to global */ 189 case 'V': 190 case 'D': 191 case 'I': 192 case 'W': 193 case 'E': 194 case 'F': /* Not officially supported */ 195 case 'A': 196 case 'S': 197 case BOOLEAN_FALSE: /* Not officially supported */ 198 break; 199 default: 200 /* clear '.' after log.tag */ 201 key[sizeof(log_namespace) - 2] = '\0'; 202 203 kp = key; 204 for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { 205 struct cache *cache = &global_cache[i]; 206 struct cache temp_cache; 207 208 if (not_locked) { 209 temp_cache = *cache; 210 if (temp_cache.pinfo != cache->pinfo) { /* check atomic */ 211 temp_cache.pinfo = NULL; 212 temp_cache.c = '\0'; 213 } 214 cache = &temp_cache; 215 } 216 if (global_change_detected) { 217 refresh_cache(cache, kp); 218 } 219 220 if (cache->c) { 221 c = cache->c; 222 break; 223 } 224 225 kp = key + base_offset; 226 } 227 break; 228 } 229 230 if (!not_locked) { 231 global_serial = current_global_serial; 232 unlock(); 233 } 234 235 switch (toupper(c)) { 236 case 'V': return ANDROID_LOG_VERBOSE; 237 case 'D': return ANDROID_LOG_DEBUG; 238 case 'I': return ANDROID_LOG_INFO; 239 case 'W': return ANDROID_LOG_WARN; 240 case 'E': return ANDROID_LOG_ERROR; 241 case 'F': /* FALLTHRU */ /* Not officially supported */ 242 case 'A': return ANDROID_LOG_FATAL; 243 case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */ 244 case 'S': return -1; /* ANDROID_LOG_SUPPRESS */ 245 } 246 return default_prio; 247 } 248 249 LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char *tag, 250 int default_prio) 251 { 252 int logLevel = __android_log_level(tag, default_prio); 253 return logLevel >= 0 && prio >= logLevel; 254 } 255 256 LIBLOG_HIDDEN int __android_log_is_debuggable() 257 { 258 static uint32_t serial; 259 static struct cache tag_cache; 260 static const char key[] = "ro.debuggable"; 261 int ret; 262 263 if (tag_cache.c) { /* ro property does not change after set */ 264 ret = tag_cache.c == '1'; 265 } else if (lock()) { 266 struct cache temp_cache = { NULL, -1, '\0' }; 267 refresh_cache(&temp_cache, key); 268 ret = temp_cache.c == '1'; 269 } else { 270 int change_detected = check_cache(&tag_cache); 271 uint32_t current_serial = __system_property_area_serial(); 272 if (current_serial != serial) { 273 change_detected = 1; 274 } 275 if (change_detected) { 276 refresh_cache(&tag_cache, key); 277 serial = current_serial; 278 } 279 ret = tag_cache.c == '1'; 280 281 unlock(); 282 } 283 284 return ret; 285 } 286 287 /* 288 * For properties that are read often, but generally remain constant. 289 * Since a change is rare, we will accept a trylock failure gracefully. 290 * Use a separate lock from is_loggable to keep contention down b/25563384. 291 */ 292 struct cache2 { 293 pthread_mutex_t lock; 294 uint32_t serial; 295 const char *key_persist; 296 struct cache cache_persist; 297 const char *key_ro; 298 struct cache cache_ro; 299 unsigned char (*const evaluate)(const struct cache2 *self); 300 }; 301 302 static inline unsigned char do_cache2(struct cache2 *self) 303 { 304 uint32_t current_serial; 305 int change_detected; 306 unsigned char c; 307 308 if (pthread_mutex_trylock(&self->lock)) { 309 /* We are willing to accept some race in this context */ 310 return self->evaluate(self); 311 } 312 313 change_detected = check_cache(&self->cache_persist) 314 || check_cache(&self->cache_ro); 315 current_serial = __system_property_area_serial(); 316 if (current_serial != self->serial) { 317 change_detected = 1; 318 } 319 if (change_detected) { 320 refresh_cache(&self->cache_persist, self->key_persist); 321 refresh_cache(&self->cache_ro, self->key_ro); 322 self->serial = current_serial; 323 } 324 c = self->evaluate(self); 325 326 pthread_mutex_unlock(&self->lock); 327 328 return c; 329 } 330 331 static unsigned char evaluate_persist_ro(const struct cache2 *self) 332 { 333 unsigned char c = self->cache_persist.c; 334 335 if (c) { 336 return c; 337 } 338 339 return self->cache_ro.c; 340 } 341 342 /* 343 * Timestamp state generally remains constant, but can change at any time 344 * to handle developer requirements. 345 */ 346 LIBLOG_ABI_PUBLIC clockid_t android_log_clockid() 347 { 348 static struct cache2 clockid = { 349 PTHREAD_MUTEX_INITIALIZER, 350 0, 351 "persist.logd.timestamp", 352 { NULL, -1, '\0' }, 353 "ro.logd.timestamp", 354 { NULL, -1, '\0' }, 355 evaluate_persist_ro 356 }; 357 358 return (tolower(do_cache2(&clockid)) == 'm') 359 ? CLOCK_MONOTONIC 360 : CLOCK_REALTIME; 361 } 362 363 /* 364 * Security state generally remains constant, but the DO must be able 365 * to turn off logging should it become spammy after an attack is detected. 366 */ 367 static unsigned char evaluate_security(const struct cache2 *self) 368 { 369 unsigned char c = self->cache_ro.c; 370 371 return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE); 372 } 373 374 LIBLOG_ABI_PUBLIC int __android_log_security() 375 { 376 static struct cache2 security = { 377 PTHREAD_MUTEX_INITIALIZER, 378 0, 379 "persist.logd.security", 380 { NULL, -1, BOOLEAN_FALSE }, 381 "ro.device_owner", 382 { NULL, -1, BOOLEAN_FALSE }, 383 evaluate_security 384 }; 385 386 return do_cache2(&security); 387 } 388