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