blob: 7a8e33f0d96ff24f97a6e60716ab7894d61ea6ae [file] [log] [blame]
Mark Salyzyn95687052014-10-02 11:12:28 -07001/*
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 Salyzync1584562015-03-12 15:46:29 -070018#include <pthread.h>
19#include <stdlib.h>
Mark Salyzyn95687052014-10-02 11:12:28 -070020#include <string.h>
Mark Salyzync1584562015-03-12 15:46:29 -070021#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
22#include <sys/_system_properties.h>
Mark Salyzyn95687052014-10-02 11:12:28 -070023
24#include <android/log.h>
25
Mark Salyzync1584562015-03-12 15:46:29 -070026struct cache {
27 const prop_info *pinfo;
28 uint32_t serial;
29 char c;
30};
31
32static void refresh_cache(struct cache *cache, const char *key)
Mark Salyzyn95687052014-10-02 11:12:28 -070033{
Mark Salyzync1584562015-03-12 15:46:29 -070034 uint32_t serial;
Mark Salyzyn95687052014-10-02 11:12:28 -070035 char buf[PROP_VALUE_MAX];
36
Mark Salyzync1584562015-03-12 15:46:29 -070037 if (!cache->pinfo) {
38 cache->pinfo = __system_property_find(key);
39 if (!cache->pinfo) {
40 return;
41 }
Mark Salyzyn95687052014-10-02 11:12:28 -070042 }
Mark Salyzync1584562015-03-12 15:46:29 -070043 serial = __system_property_serial(cache->pinfo);
44 if (serial == cache->serial) {
45 return;
46 }
47 cache->serial = serial;
48 __system_property_read(cache->pinfo, 0, buf);
49 cache->c = buf[0];
50}
Mark Salyzyn95687052014-10-02 11:12:28 -070051
Mark Salyzync1584562015-03-12 15:46:29 -070052static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
53
54static int __android_log_level(const char *tag, int def)
55{
56 /* sizeof() is used on this array below */
57 static const char log_namespace[] = "persist.log.tag.";
58 static const size_t base_offset = 8; /* skip "persist." */
59 /* calculate the size of our key temporary buffer */
60 const size_t taglen = (tag && *tag) ? strlen(tag) : 0;
61 /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
62 char key[sizeof(log_namespace) + taglen];
63 char *kp;
64 size_t i;
65 char c = 0;
66 /*
67 * Single layer cache of four properties. Priorities are:
68 * log.tag.<tag>
69 * persist.log.tag.<tag>
70 * log.tag
71 * persist.log.tag
72 * Where the missing tag matches all tags and becomes the
73 * system global default. We do not support ro.log.tag* .
74 */
75 static char *last_tag;
76 static uint32_t global_serial;
77 uint32_t current_global_serial;
78 static struct cache tag_cache[2] = {
79 { NULL, -1, 0 },
80 { NULL, -1, 0 }
81 };
82 static struct cache global_cache[2] = {
83 { NULL, -1, 0 },
84 { NULL, -1, 0 }
85 };
86
87 strcpy(key, log_namespace);
88
89 pthread_mutex_lock(&lock);
90
91 current_global_serial = __system_property_area_serial();
92
93 if (taglen) {
94 uint32_t current_local_serial = current_global_serial;
95
96 if (!last_tag || strcmp(last_tag, tag)) {
97 /* invalidate log.tag.<tag> cache */
98 for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
99 tag_cache[i].pinfo = NULL;
100 tag_cache[i].serial = -1;
101 tag_cache[i].c = '\0';
102 }
103 free(last_tag);
104 last_tag = NULL;
105 current_global_serial = -1;
106 }
107 if (!last_tag) {
108 last_tag = strdup(tag);
109 }
Mark Salyzyn95687052014-10-02 11:12:28 -0700110 strcpy(key + sizeof(log_namespace) - 1, tag);
111
Mark Salyzync1584562015-03-12 15:46:29 -0700112 kp = key;
113 for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
114 if (current_local_serial != global_serial) {
115 refresh_cache(&tag_cache[i], kp);
116 }
117
118 if (tag_cache[i].c) {
119 c = tag_cache[i].c;
120 break;
121 }
122
123 kp = key + base_offset;
Mark Salyzyn1f028b22014-10-08 15:58:40 -0700124 }
Mark Salyzyn95687052014-10-02 11:12:28 -0700125 }
Mark Salyzync1584562015-03-12 15:46:29 -0700126
127 switch (toupper(c)) { /* if invalid, resort to global */
128 case 'V':
129 case 'D':
130 case 'I':
131 case 'W':
132 case 'E':
133 case 'F': /* Not officially supported */
134 case 'A':
135 case 'S':
136 break;
137 default:
138 /* clear '.' after log.tag */
139 key[sizeof(log_namespace) - 2] = '\0';
140
141 kp = key;
142 for(i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
143 if (current_global_serial != global_serial) {
144 refresh_cache(&global_cache[i], kp);
145 }
146
147 if (global_cache[i].c) {
148 c = global_cache[i].c;
149 break;
150 }
151
152 kp = key + base_offset;
153 }
154 break;
155 }
156
157 global_serial = current_global_serial;
158
159 pthread_mutex_unlock(&lock);
160
161 switch (toupper(c)) {
162 case 'V': return ANDROID_LOG_VERBOSE;
163 case 'D': return ANDROID_LOG_DEBUG;
164 case 'I': return ANDROID_LOG_INFO;
165 case 'W': return ANDROID_LOG_WARN;
166 case 'E': return ANDROID_LOG_ERROR;
167 case 'F': /* FALLTHRU */ /* Not officially supported */
168 case 'A': return ANDROID_LOG_FATAL;
169 case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
Mark Salyzyn95687052014-10-02 11:12:28 -0700170 }
171 return def;
172}
173
174int __android_log_is_loggable(int prio, const char *tag, int def)
175{
Mark Salyzyn1f028b22014-10-08 15:58:40 -0700176 int logLevel = __android_log_level(tag, def);
Mark Salyzyn95687052014-10-02 11:12:28 -0700177 return logLevel >= 0 && prio >= logLevel;
178}