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 <log/log_properties.h>
18
19 #include <ctype.h>
20 #include <pthread.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include <algorithm>
26
27 #include <android-base/macros.h>
28
29 #include <private/android_logger.h>
30
31 #include "logger_write.h"
32
33 #ifdef __ANDROID__
34 #include <sys/system_properties.h>
35
36 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
37
trylock()38 static bool trylock() {
39 /*
40 * If we trigger a signal handler in the middle of locked activity and the
41 * signal handler logs a message, we could get into a deadlock state.
42 */
43 /*
44 * Any contention, and we can turn around and use the non-cached method
45 * in less time than the system call associated with a mutex to deal with
46 * the contention.
47 */
48 return pthread_mutex_trylock(&lock_loggable) == 0;
49 }
50
unlock()51 static void unlock() {
52 pthread_mutex_unlock(&lock_loggable);
53 }
54
55 struct cache {
56 const prop_info* pinfo;
57 uint32_t serial;
58 };
59
60 struct cache_char {
61 struct cache cache;
62 unsigned char c;
63 };
64
check_cache(struct cache * cache)65 static int check_cache(struct cache* cache) {
66 return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial;
67 }
68
69 #define BOOLEAN_TRUE 0xFF
70 #define BOOLEAN_FALSE 0xFE
71
refresh_cache(struct cache_char * cache,const char * key)72 static void refresh_cache(struct cache_char* cache, const char* key) {
73 char buf[PROP_VALUE_MAX];
74
75 if (!cache->cache.pinfo) {
76 cache->cache.pinfo = __system_property_find(key);
77 if (!cache->cache.pinfo) {
78 return;
79 }
80 }
81 cache->cache.serial = __system_property_serial(cache->cache.pinfo);
82 __system_property_read(cache->cache.pinfo, 0, buf);
83 switch (buf[0]) {
84 case 't':
85 case 'T':
86 cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
87 break;
88 case 'f':
89 case 'F':
90 cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
91 break;
92 default:
93 cache->c = buf[0];
94 }
95 }
96
__android_log_level(const char * tag,size_t tag_len)97 static int __android_log_level(const char* tag, size_t tag_len) {
98 if (tag == nullptr || tag_len == 0) {
99 auto& tag_string = GetDefaultTag();
100 tag = tag_string.c_str();
101 tag_len = tag_string.size();
102 }
103
104 /*
105 * Single layer cache of four properties. Priorities are:
106 * log.tag.<tag>
107 * persist.log.tag.<tag>
108 * log.tag
109 * persist.log.tag
110 * Where the missing tag matches all tags and becomes the
111 * system global default. We do not support ro.log.tag* .
112 */
113 static std::string* last_tag = new std::string;
114 static uint32_t global_serial;
115 uint32_t current_global_serial;
116 static cache_char tag_cache[2];
117 static cache_char global_cache[2];
118
119 static const char* log_namespace = "persist.log.tag.";
120 char key[strlen(log_namespace) + tag_len + 1];
121 strcpy(key, log_namespace);
122
123 bool locked = trylock();
124 bool change_detected, global_change_detected;
125 global_change_detected = change_detected = !locked;
126
127 char c = 0;
128 if (locked) {
129 // Check all known serial numbers for changes.
130 for (size_t i = 0; i < arraysize(tag_cache); ++i) {
131 if (check_cache(&tag_cache[i].cache)) {
132 change_detected = true;
133 }
134 }
135 for (size_t i = 0; i < arraysize(global_cache); ++i) {
136 if (check_cache(&global_cache[i].cache)) {
137 global_change_detected = true;
138 }
139 }
140
141 current_global_serial = __system_property_area_serial();
142 if (current_global_serial != global_serial) {
143 global_change_detected = change_detected = true;
144 }
145 }
146
147 if (tag_len != 0) {
148 bool local_change_detected = change_detected;
149 if (locked) {
150 // compare() rather than == because tag isn't guaranteed 0-terminated.
151 if (last_tag->compare(0, last_tag->size(), tag, tag_len) != 0) {
152 // Invalidate log.tag.<tag> cache.
153 for (size_t i = 0; i < arraysize(tag_cache); ++i) {
154 tag_cache[i].cache.pinfo = NULL;
155 tag_cache[i].c = '\0';
156 }
157 last_tag->assign(tag, tag_len);
158 local_change_detected = true;
159 }
160 }
161 *stpncpy(key + strlen(log_namespace), tag, tag_len) = '\0';
162
163 for (size_t i = 0; i < arraysize(tag_cache); ++i) {
164 cache_char* cache = &tag_cache[i];
165 cache_char temp_cache;
166
167 if (!locked) {
168 temp_cache.cache.pinfo = NULL;
169 temp_cache.c = '\0';
170 cache = &temp_cache;
171 }
172 if (local_change_detected) {
173 refresh_cache(cache, i == 0 ? key : key + strlen("persist."));
174 }
175
176 if (cache->c) {
177 c = cache->c;
178 break;
179 }
180 }
181 }
182
183 switch (toupper(c)) { /* if invalid, resort to global */
184 case 'V':
185 case 'D':
186 case 'I':
187 case 'W':
188 case 'E':
189 case 'F': /* Not officially supported */
190 case 'A':
191 case 'S':
192 case BOOLEAN_FALSE: /* Not officially supported */
193 break;
194 default:
195 /* clear '.' after log.tag */
196 key[strlen(log_namespace) - 1] = '\0';
197
198 for (size_t i = 0; i < arraysize(global_cache); ++i) {
199 cache_char* cache = &global_cache[i];
200 cache_char temp_cache;
201
202 if (!locked) {
203 temp_cache = *cache;
204 if (temp_cache.cache.pinfo != cache->cache.pinfo) { // check atomic
205 temp_cache.cache.pinfo = NULL;
206 temp_cache.c = '\0';
207 }
208 cache = &temp_cache;
209 }
210 if (global_change_detected) {
211 refresh_cache(cache, i == 0 ? key : key + strlen("persist."));
212 }
213
214 if (cache->c) {
215 c = cache->c;
216 break;
217 }
218 }
219 break;
220 }
221
222 if (locked) {
223 global_serial = current_global_serial;
224 unlock();
225 }
226
227 switch (toupper(c)) {
228 /* clang-format off */
229 case 'V': return ANDROID_LOG_VERBOSE;
230 case 'D': return ANDROID_LOG_DEBUG;
231 case 'I': return ANDROID_LOG_INFO;
232 case 'W': return ANDROID_LOG_WARN;
233 case 'E': return ANDROID_LOG_ERROR;
234 case 'F': /* FALLTHRU */ /* Not officially supported */
235 case 'A': return ANDROID_LOG_FATAL;
236 case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
237 case 'S': return ANDROID_LOG_SILENT;
238 /* clang-format on */
239 }
240 return -1;
241 }
242
__android_log_is_loggable_len(int prio,const char * tag,size_t len,int default_prio)243 int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
244 int minimum_log_priority = __android_log_get_minimum_priority();
245 int property_log_level = __android_log_level(tag, len);
246
247 if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
248 return prio >= std::min(property_log_level, minimum_log_priority);
249 } else if (property_log_level >= 0) {
250 return prio >= property_log_level;
251 } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
252 return prio >= minimum_log_priority;
253 } else {
254 return prio >= default_prio;
255 }
256 }
257
__android_log_is_loggable(int prio,const char * tag,int default_prio)258 int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
259 auto len = tag ? strlen(tag) : 0;
260 return __android_log_is_loggable_len(prio, tag, len, default_prio);
261 }
262
__android_log_is_debuggable()263 int __android_log_is_debuggable() {
264 static int is_debuggable = [] {
265 char value[PROP_VALUE_MAX] = {};
266 return __system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1");
267 }();
268
269 return is_debuggable;
270 }
271
__android_log_security()272 int __android_log_security() {
273 static pthread_mutex_t security_lock = PTHREAD_MUTEX_INITIALIZER;
274 static cache_char security_prop = {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE};
275 static uint32_t security_serial = 0;
276
277 if (pthread_mutex_trylock(&security_lock)) {
278 /* We are willing to accept some race in this context */
279 return security_prop.c == BOOLEAN_TRUE;
280 }
281
282 int change_detected = check_cache(&security_prop.cache);
283 uint32_t current_serial = __system_property_area_serial();
284 if (current_serial != security_serial) {
285 change_detected = 1;
286 }
287 if (change_detected) {
288 refresh_cache(&security_prop, "persist.logd.security");
289 security_serial = current_serial;
290 }
291
292 int res = security_prop.c == BOOLEAN_TRUE;
293
294 pthread_mutex_unlock(&security_lock);
295
296 return res;
297 }
298
299 #else
300
__android_log_is_loggable(int prio,const char *,int)301 int __android_log_is_loggable(int prio, const char*, int) {
302 int minimum_priority = __android_log_get_minimum_priority();
303 if (minimum_priority == ANDROID_LOG_DEFAULT) {
304 minimum_priority = ANDROID_LOG_INFO;
305 }
306 return prio >= minimum_priority;
307 }
308
__android_log_is_loggable_len(int prio,const char *,size_t,int def)309 int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
310 return __android_log_is_loggable(prio, nullptr, def);
311 }
312
__android_log_is_debuggable()313 int __android_log_is_debuggable() {
314 return 1;
315 }
316
__android_log_security()317 int __android_log_security() {
318 return 0;
319 }
320
321 #endif
322