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 <stdbool.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 23 #include <sys/_system_properties.h> 24 #include <unistd.h> 25 26 #include <private/android_logger.h> 27 28 #include "log_portability.h" 29 30 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER; 31 32 static int lock() { 33 /* 34 * If we trigger a signal handler in the middle of locked activity and the 35 * signal handler logs a message, we could get into a deadlock state. 36 */ 37 /* 38 * Any contention, and we can turn around and use the non-cached method 39 * in less time than the system call associated with a mutex to deal with 40 * the contention. 41 */ 42 return pthread_mutex_trylock(&lock_loggable); 43 } 44 45 static void unlock() { 46 pthread_mutex_unlock(&lock_loggable); 47 } 48 49 struct cache { 50 const prop_info* pinfo; 51 uint32_t serial; 52 }; 53 54 struct cache_char { 55 struct cache cache; 56 unsigned char c; 57 }; 58 59 static int check_cache(struct cache* cache) { 60 return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial; 61 } 62 63 #define BOOLEAN_TRUE 0xFF 64 #define BOOLEAN_FALSE 0xFE 65 66 static void refresh_cache(struct cache_char* cache, const char* key) { 67 char buf[PROP_VALUE_MAX]; 68 69 if (!cache->cache.pinfo) { 70 cache->cache.pinfo = __system_property_find(key); 71 if (!cache->cache.pinfo) { 72 return; 73 } 74 } 75 cache->cache.serial = __system_property_serial(cache->cache.pinfo); 76 __system_property_read(cache->cache.pinfo, 0, buf); 77 switch (buf[0]) { 78 case 't': 79 case 'T': 80 cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE; 81 break; 82 case 'f': 83 case 'F': 84 cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE; 85 break; 86 default: 87 cache->c = buf[0]; 88 } 89 } 90 91 static int __android_log_level(const char* tag, size_t len, int default_prio) { 92 /* sizeof() is used on this array below */ 93 static const char log_namespace[] = "persist.log.tag."; 94 static const size_t base_offset = 8; /* skip "persist." */ 95 /* calculate the size of our key temporary buffer */ 96 const size_t taglen = tag ? len : 0; 97 /* sizeof(log_namespace) = strlen(log_namespace) + 1 */ 98 char key[sizeof(log_namespace) + taglen]; 99 char* kp; 100 size_t i; 101 char c = 0; 102 /* 103 * Single layer cache of four properties. Priorities are: 104 * log.tag.<tag> 105 * persist.log.tag.<tag> 106 * log.tag 107 * persist.log.tag 108 * Where the missing tag matches all tags and becomes the 109 * system global default. We do not support ro.log.tag* . 110 */ 111 static char* last_tag; 112 static size_t last_tag_len; 113 static uint32_t global_serial; 114 /* some compilers erroneously see uninitialized use. !not_locked */ 115 uint32_t current_global_serial = 0; 116 static struct cache_char tag_cache[2]; 117 static struct cache_char global_cache[2]; 118 int change_detected; 119 int global_change_detected; 120 int not_locked; 121 122 strcpy(key, log_namespace); 123 124 global_change_detected = change_detected = not_locked = lock(); 125 126 if (!not_locked) { 127 /* 128 * check all known serial numbers to changes. 129 */ 130 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { 131 if (check_cache(&tag_cache[i].cache)) { 132 change_detected = 1; 133 } 134 } 135 for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { 136 if (check_cache(&global_cache[i].cache)) { 137 global_change_detected = 1; 138 } 139 } 140 141 current_global_serial = __system_property_area_serial(); 142 if (current_global_serial != global_serial) { 143 change_detected = 1; 144 global_change_detected = 1; 145 } 146 } 147 148 if (taglen) { 149 int local_change_detected = change_detected; 150 if (!not_locked) { 151 if (!last_tag || !last_tag[0] || (last_tag[0] != tag[0]) || 152 strncmp(last_tag + 1, tag + 1, last_tag_len - 1)) { 153 /* invalidate log.tag.<tag> cache */ 154 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { 155 tag_cache[i].cache.pinfo = NULL; 156 tag_cache[i].c = '\0'; 157 } 158 if (last_tag) last_tag[0] = '\0'; 159 local_change_detected = 1; 160 } 161 if (!last_tag || !last_tag[0]) { 162 if (!last_tag) { 163 last_tag = calloc(1, len + 1); 164 last_tag_len = 0; 165 if (last_tag) last_tag_len = len + 1; 166 } else if (len >= last_tag_len) { 167 last_tag = realloc(last_tag, len + 1); 168 last_tag_len = 0; 169 if (last_tag) last_tag_len = len + 1; 170 } 171 if (last_tag) { 172 strncpy(last_tag, tag, len); 173 last_tag[len] = '\0'; 174 } 175 } 176 } 177 strncpy(key + sizeof(log_namespace) - 1, tag, len); 178 key[sizeof(log_namespace) - 1 + len] = '\0'; 179 180 kp = key; 181 for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) { 182 struct cache_char* cache = &tag_cache[i]; 183 struct cache_char temp_cache; 184 185 if (not_locked) { 186 temp_cache.cache.pinfo = NULL; 187 temp_cache.c = '\0'; 188 cache = &temp_cache; 189 } 190 if (local_change_detected) { 191 refresh_cache(cache, kp); 192 } 193 194 if (cache->c) { 195 c = cache->c; 196 break; 197 } 198 199 kp = key + base_offset; 200 } 201 } 202 203 switch (toupper(c)) { /* if invalid, resort to global */ 204 case 'V': 205 case 'D': 206 case 'I': 207 case 'W': 208 case 'E': 209 case 'F': /* Not officially supported */ 210 case 'A': 211 case 'S': 212 case BOOLEAN_FALSE: /* Not officially supported */ 213 break; 214 default: 215 /* clear '.' after log.tag */ 216 key[sizeof(log_namespace) - 2] = '\0'; 217 218 kp = key; 219 for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) { 220 struct cache_char* cache = &global_cache[i]; 221 struct cache_char temp_cache; 222 223 if (not_locked) { 224 temp_cache = *cache; 225 if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */ 226 temp_cache.cache.pinfo = NULL; 227 temp_cache.c = '\0'; 228 } 229 cache = &temp_cache; 230 } 231 if (global_change_detected) { 232 refresh_cache(cache, kp); 233 } 234 235 if (cache->c) { 236 c = cache->c; 237 break; 238 } 239 240 kp = key + base_offset; 241 } 242 break; 243 } 244 245 if (!not_locked) { 246 global_serial = current_global_serial; 247 unlock(); 248 } 249 250 switch (toupper(c)) { 251 /* clang-format off */ 252 case 'V': return ANDROID_LOG_VERBOSE; 253 case 'D': return ANDROID_LOG_DEBUG; 254 case 'I': return ANDROID_LOG_INFO; 255 case 'W': return ANDROID_LOG_WARN; 256 case 'E': return ANDROID_LOG_ERROR; 257 case 'F': /* FALLTHRU */ /* Not officially supported */ 258 case 'A': return ANDROID_LOG_FATAL; 259 case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */ 260 case 'S': return -1; /* ANDROID_LOG_SUPPRESS */ 261 /* clang-format on */ 262 } 263 return default_prio; 264 } 265 266 LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio, const char* tag, 267 size_t len, 268 int default_prio) { 269 int logLevel = __android_log_level(tag, len, default_prio); 270 return logLevel >= 0 && prio >= logLevel; 271 } 272 273 LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char* tag, 274 int default_prio) { 275 int logLevel = 276 __android_log_level(tag, (tag && *tag) ? strlen(tag) : 0, default_prio); 277 return logLevel >= 0 && prio >= logLevel; 278 } 279 280 LIBLOG_ABI_PUBLIC int __android_log_is_debuggable() { 281 static uint32_t serial; 282 static struct cache_char tag_cache; 283 static const char key[] = "ro.debuggable"; 284 int ret; 285 286 if (tag_cache.c) { /* ro property does not change after set */ 287 ret = tag_cache.c == '1'; 288 } else if (lock()) { 289 struct cache_char temp_cache = { { NULL, -1 }, '\0' }; 290 refresh_cache(&temp_cache, key); 291 ret = temp_cache.c == '1'; 292 } else { 293 int change_detected = check_cache(&tag_cache.cache); 294 uint32_t current_serial = __system_property_area_serial(); 295 if (current_serial != serial) { 296 change_detected = 1; 297 } 298 if (change_detected) { 299 refresh_cache(&tag_cache, key); 300 serial = current_serial; 301 } 302 ret = tag_cache.c == '1'; 303 304 unlock(); 305 } 306 307 return ret; 308 } 309 310 /* 311 * For properties that are read often, but generally remain constant. 312 * Since a change is rare, we will accept a trylock failure gracefully. 313 * Use a separate lock from is_loggable to keep contention down b/25563384. 314 */ 315 struct cache2_char { 316 pthread_mutex_t lock; 317 uint32_t serial; 318 const char* key_persist; 319 struct cache_char cache_persist; 320 const char* key_ro; 321 struct cache_char cache_ro; 322 unsigned char (*const evaluate)(const struct cache2_char* self); 323 }; 324 325 static inline unsigned char do_cache2_char(struct cache2_char* self) { 326 uint32_t current_serial; 327 int change_detected; 328 unsigned char c; 329 330 if (pthread_mutex_trylock(&self->lock)) { 331 /* We are willing to accept some race in this context */ 332 return self->evaluate(self); 333 } 334 335 change_detected = check_cache(&self->cache_persist.cache) || 336 check_cache(&self->cache_ro.cache); 337 current_serial = __system_property_area_serial(); 338 if (current_serial != self->serial) { 339 change_detected = 1; 340 } 341 if (change_detected) { 342 refresh_cache(&self->cache_persist, self->key_persist); 343 refresh_cache(&self->cache_ro, self->key_ro); 344 self->serial = current_serial; 345 } 346 c = self->evaluate(self); 347 348 pthread_mutex_unlock(&self->lock); 349 350 return c; 351 } 352 353 static unsigned char evaluate_persist_ro(const struct cache2_char* self) { 354 unsigned char c = self->cache_persist.c; 355 356 if (c) { 357 return c; 358 } 359 360 return self->cache_ro.c; 361 } 362 363 /* 364 * Timestamp state generally remains constant, but can change at any time 365 * to handle developer requirements. 366 */ 367 LIBLOG_ABI_PUBLIC clockid_t android_log_clockid() { 368 static struct cache2_char clockid = { 369 PTHREAD_MUTEX_INITIALIZER, 0, 370 "persist.logd.timestamp", { { NULL, -1 }, '\0' }, 371 "ro.logd.timestamp", { { NULL, -1 }, '\0' }, 372 evaluate_persist_ro 373 }; 374 375 return (tolower(do_cache2_char(&clockid)) == 'm') ? CLOCK_MONOTONIC 376 : CLOCK_REALTIME; 377 } 378 379 /* 380 * Security state generally remains constant, but the DO must be able 381 * to turn off logging should it become spammy after an attack is detected. 382 */ 383 static unsigned char evaluate_security(const struct cache2_char* self) { 384 unsigned char c = self->cache_ro.c; 385 386 return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE); 387 } 388 389 LIBLOG_ABI_PUBLIC int __android_log_security() { 390 static struct cache2_char security = { 391 PTHREAD_MUTEX_INITIALIZER, 0, 392 "persist.logd.security", { { NULL, -1 }, BOOLEAN_FALSE }, 393 "ro.device_owner", { { NULL, -1 }, BOOLEAN_FALSE }, 394 evaluate_security 395 }; 396 397 return do_cache2_char(&security); 398 } 399 400 /* 401 * Interface that represents the logd buffer size determination so that others 402 * need not guess our intentions. 403 */ 404 405 /* Property helper */ 406 static bool check_flag(const char* prop, const char* flag) { 407 const char* cp = strcasestr(prop, flag); 408 if (!cp) { 409 return false; 410 } 411 /* We only will document comma (,) */ 412 static const char sep[] = ",:;|+ \t\f"; 413 if ((cp != prop) && !strchr(sep, cp[-1])) { 414 return false; 415 } 416 cp += strlen(flag); 417 return !*cp || !!strchr(sep, *cp); 418 } 419 420 /* cache structure */ 421 struct cache_property { 422 struct cache cache; 423 char property[PROP_VALUE_MAX]; 424 }; 425 426 static void refresh_cache_property(struct cache_property* cache, 427 const char* key) { 428 if (!cache->cache.pinfo) { 429 cache->cache.pinfo = __system_property_find(key); 430 if (!cache->cache.pinfo) { 431 return; 432 } 433 } 434 cache->cache.serial = __system_property_serial(cache->cache.pinfo); 435 __system_property_read(cache->cache.pinfo, 0, cache->property); 436 } 437 438 /* get boolean with the logger twist that supports eng adjustments */ 439 LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key, 440 int flag) { 441 struct cache_property property = { { NULL, -1 }, { 0 } }; 442 if (flag & BOOL_DEFAULT_FLAG_PERSIST) { 443 char newkey[strlen("persist.") + strlen(key) + 1]; 444 snprintf(newkey, sizeof(newkey), "ro.%s", key); 445 refresh_cache_property(&property, newkey); 446 property.cache.pinfo = NULL; 447 property.cache.serial = -1; 448 snprintf(newkey, sizeof(newkey), "persist.%s", key); 449 refresh_cache_property(&property, newkey); 450 property.cache.pinfo = NULL; 451 property.cache.serial = -1; 452 } 453 454 refresh_cache_property(&property, key); 455 456 if (check_flag(property.property, "true")) { 457 return true; 458 } 459 if (check_flag(property.property, "false")) { 460 return false; 461 } 462 if (property.property[0]) { 463 flag &= ~(BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE); 464 } 465 if (check_flag(property.property, "eng")) { 466 flag |= BOOL_DEFAULT_FLAG_ENG; 467 } 468 /* this is really a "not" flag */ 469 if (check_flag(property.property, "svelte")) { 470 flag |= BOOL_DEFAULT_FLAG_SVELTE; 471 } 472 473 /* Sanity Check */ 474 if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) { 475 flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE; 476 flag |= BOOL_DEFAULT_TRUE; 477 } 478 479 if ((flag & BOOL_DEFAULT_FLAG_SVELTE) && 480 __android_logger_property_get_bool("ro.config.low_ram", 481 BOOL_DEFAULT_FALSE)) { 482 return false; 483 } 484 if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) { 485 return false; 486 } 487 488 return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE; 489 } 490 491 LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value) { 492 static long pages, pagesize; 493 unsigned long maximum; 494 495 if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) { 496 return false; 497 } 498 499 if (!pages) { 500 pages = sysconf(_SC_PHYS_PAGES); 501 } 502 if (pages < 1) { 503 return true; 504 } 505 506 if (!pagesize) { 507 pagesize = sysconf(_SC_PAGESIZE); 508 if (pagesize <= 1) { 509 pagesize = PAGE_SIZE; 510 } 511 } 512 513 /* maximum memory impact a somewhat arbitrary ~3% */ 514 pages = (pages + 31) / 32; 515 maximum = pages * pagesize; 516 517 if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) { 518 return true; 519 } 520 521 return value <= maximum; 522 } 523 524 struct cache2_property_size { 525 pthread_mutex_t lock; 526 uint32_t serial; 527 const char* key_persist; 528 struct cache_property cache_persist; 529 const char* key_ro; 530 struct cache_property cache_ro; 531 unsigned long (*const evaluate)(const struct cache2_property_size* self); 532 }; 533 534 static inline unsigned long do_cache2_property_size( 535 struct cache2_property_size* self) { 536 uint32_t current_serial; 537 int change_detected; 538 unsigned long v; 539 540 if (pthread_mutex_trylock(&self->lock)) { 541 /* We are willing to accept some race in this context */ 542 return self->evaluate(self); 543 } 544 545 change_detected = check_cache(&self->cache_persist.cache) || 546 check_cache(&self->cache_ro.cache); 547 current_serial = __system_property_area_serial(); 548 if (current_serial != self->serial) { 549 change_detected = 1; 550 } 551 if (change_detected) { 552 refresh_cache_property(&self->cache_persist, self->key_persist); 553 refresh_cache_property(&self->cache_ro, self->key_ro); 554 self->serial = current_serial; 555 } 556 v = self->evaluate(self); 557 558 pthread_mutex_unlock(&self->lock); 559 560 return v; 561 } 562 563 static unsigned long property_get_size_from_cache( 564 const struct cache_property* cache) { 565 char* cp; 566 unsigned long value = strtoul(cache->property, &cp, 10); 567 568 switch (*cp) { 569 case 'm': 570 case 'M': 571 value *= 1024; 572 /* FALLTHRU */ 573 case 'k': 574 case 'K': 575 value *= 1024; 576 /* FALLTHRU */ 577 case '\0': 578 break; 579 580 default: 581 value = 0; 582 } 583 584 if (!__android_logger_valid_buffer_size(value)) { 585 value = 0; 586 } 587 588 return value; 589 } 590 591 static unsigned long evaluate_property_get_size( 592 const struct cache2_property_size* self) { 593 unsigned long size = property_get_size_from_cache(&self->cache_persist); 594 if (size) { 595 return size; 596 } 597 return property_get_size_from_cache(&self->cache_ro); 598 } 599 600 LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId) { 601 static const char global_tunable[] = "persist.logd.size"; /* Settings App */ 602 static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */ 603 static struct cache2_property_size global = { 604 /* clang-format off */ 605 PTHREAD_MUTEX_INITIALIZER, 0, 606 global_tunable, { { NULL, -1 }, {} }, 607 global_default, { { NULL, -1 }, {} }, 608 evaluate_property_get_size 609 /* clang-format on */ 610 }; 611 char key_persist[strlen(global_tunable) + strlen(".security") + 1]; 612 char key_ro[strlen(global_default) + strlen(".security") + 1]; 613 struct cache2_property_size local = { 614 /* clang-format off */ 615 PTHREAD_MUTEX_INITIALIZER, 0, 616 key_persist, { { NULL, -1 }, {} }, 617 key_ro, { { NULL, -1 }, {} }, 618 evaluate_property_get_size 619 /* clang-format on */ 620 }; 621 unsigned long property_size, default_size; 622 623 default_size = do_cache2_property_size(&global); 624 if (!default_size) { 625 default_size = __android_logger_property_get_bool("ro.config.low_ram", 626 BOOL_DEFAULT_FALSE) 627 ? LOG_BUFFER_MIN_SIZE /* 64K */ 628 : LOG_BUFFER_SIZE; /* 256K */ 629 } 630 631 snprintf(key_persist, sizeof(key_persist), "%s.%s", global_tunable, 632 android_log_id_to_name(logId)); 633 snprintf(key_ro, sizeof(key_ro), "%s.%s", global_default, 634 android_log_id_to_name(logId)); 635 property_size = do_cache2_property_size(&local); 636 637 if (!property_size) { 638 property_size = default_size; 639 } 640 641 if (!property_size) { 642 property_size = LOG_BUFFER_SIZE; 643 } 644 645 return property_size; 646 } 647