summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--logd/Android.mk14
-rw-r--r--logd/CommandListener.cpp37
-rw-r--r--logd/CommandListener.h1
-rw-r--r--logd/LogBuffer.cpp6
-rw-r--r--logd/LogBuffer.h9
-rw-r--r--logd/LogStatistics.cpp7
-rw-r--r--logd/LogStatistics.h2
-rw-r--r--logd/LogTags.cpp884
-rw-r--r--logd/LogTags.h118
-rw-r--r--logd/LogUtils.h5
-rw-r--r--logd/event.logtags1
-rw-r--r--logd/logd.rc7
-rw-r--r--logd/logtagd.rc9
-rw-r--r--logd/main.cpp21
-rw-r--r--logd/tests/logd_test.cpp53
15 files changed, 1138 insertions, 36 deletions
diff --git a/logd/Android.mk b/logd/Android.mk
index 2da9782f7..9211037bb 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -21,6 +21,7 @@ LOCAL_SRC_FILES := \
21 libaudit.c \ 21 libaudit.c \
22 LogAudit.cpp \ 22 LogAudit.cpp \
23 LogKlog.cpp \ 23 LogKlog.cpp \
24 LogTags.cpp \
24 event.logtags 25 event.logtags
25 26
26LOCAL_SHARED_LIBRARIES := \ 27LOCAL_SHARED_LIBRARIES := \
@@ -38,12 +39,23 @@ LOCAL_SHARED_LIBRARIES := \
38# $(LOCAL_PATH)/$2/event.logtags) 39# $(LOCAL_PATH)/$2/event.logtags)
39# event_flag := $(call event_logtags,auditd) 40# event_flag := $(call event_logtags,auditd)
40# event_flag += $(call event_logtags,logd) 41# event_flag += $(call event_logtags,logd)
42# event_flag += $(call event_logtags,tag_def)
41# so make sure we do not regret hard-coding it as follows: 43# so make sure we do not regret hard-coding it as follows:
42event_flag := -DAUDITD_LOG_TAG=1003 -DCHATTY_LOG_TAG=1004 44event_flag := -DAUDITD_LOG_TAG=1003 -DCHATTY_LOG_TAG=1004 -DTAG_DEF_LOG_TAG=1005
43event_flag += -DLIBLOG_LOG_TAG=1006 45event_flag += -DLIBLOG_LOG_TAG=1006
44 46
45LOCAL_CFLAGS := -Werror $(event_flag) 47LOCAL_CFLAGS := -Werror $(event_flag)
46 48
47include $(BUILD_EXECUTABLE) 49include $(BUILD_EXECUTABLE)
48 50
51include $(CLEAR_VARS)
52
53LOCAL_MODULE := logtagd.rc
54LOCAL_SRC_FILES := $(LOCAL_MODULE)
55LOCAL_MODULE_CLASS := ETC
56LOCAL_MODULE_TAGS := debug
57LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
58
59include $(BUILD_PREBUILT)
60
49include $(call first-makefiles-under,$(LOCAL_PATH)) 61include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 52c67424a..74e0ea576 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17#include <arpa/inet.h> 17#include <arpa/inet.h>
18#include <ctype.h>
18#include <dirent.h> 19#include <dirent.h>
19#include <errno.h> 20#include <errno.h>
20#include <fcntl.h> 21#include <fcntl.h>
@@ -47,6 +48,7 @@ CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
47 registerCmd(new GetStatisticsCmd(buf)); 48 registerCmd(new GetStatisticsCmd(buf));
48 registerCmd(new SetPruneListCmd(buf)); 49 registerCmd(new SetPruneListCmd(buf));
49 registerCmd(new GetPruneListCmd(buf)); 50 registerCmd(new GetPruneListCmd(buf));
51 registerCmd(new GetEventTagCmd(buf));
50 registerCmd(new ReinitCmd()); 52 registerCmd(new ReinitCmd());
51 registerCmd(new ExitCmd(this)); 53 registerCmd(new ExitCmd(this));
52} 54}
@@ -284,6 +286,41 @@ int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
284 return 0; 286 return 0;
285} 287}
286 288
289CommandListener::GetEventTagCmd::GetEventTagCmd(LogBuffer *buf) :
290 LogCommand("getEventTag"),
291 mBuf(*buf) {
292}
293
294int CommandListener::GetEventTagCmd::runCommand(SocketClient *cli,
295 int argc, char ** argv) {
296 setname();
297 uid_t uid = cli->getUid();
298 if (clientHasLogCredentials(cli)) {
299 uid = AID_ROOT;
300 }
301
302 const char *name = NULL;
303 const char *format = NULL;
304 for (int i = 1; i < argc; ++i) {
305 static const char _name[] = "name=";
306 if (!strncmp(argv[i], _name, strlen(_name))) {
307 name = argv[i] + strlen(_name);
308 continue;
309 }
310
311 static const char _format[] = "format=";
312 if (!strncmp(argv[i], _format, strlen(_format))) {
313 format = argv[i] + strlen(_format);
314 continue;
315 }
316 }
317
318 cli->sendMsg(package_string(mBuf.formatGetEventTag(uid,
319 name, format)).c_str());
320
321 return 0;
322}
323
287CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") { 324CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
288} 325}
289 326
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index 5d5017785..39de03b5a 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -61,6 +61,7 @@ private:
61 LogBufferCmd(GetStatistics); 61 LogBufferCmd(GetStatistics);
62 LogBufferCmd(GetPruneList); 62 LogBufferCmd(GetPruneList);
63 LogBufferCmd(SetPruneList); 63 LogBufferCmd(SetPruneList);
64 LogBufferCmd(GetEventTag);
64 65
65#define LogCmd(name) \ 66#define LogCmd(name) \
66 class name##Cmd : public LogCommand { \ 67 class name##Cmd : public LogCommand { \
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 820ff64d1..7613c1e98 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -199,15 +199,13 @@ int LogBuffer::log(log_id_t log_id, log_time realtime,
199 if (log_id != LOG_ID_SECURITY) { 199 if (log_id != LOG_ID_SECURITY) {
200 int prio = ANDROID_LOG_INFO; 200 int prio = ANDROID_LOG_INFO;
201 const char *tag = NULL; 201 const char *tag = NULL;
202 size_t len = 0;
203 if (log_id == LOG_ID_EVENTS) { 202 if (log_id == LOG_ID_EVENTS) {
204 tag = android::tagToName(&len, elem->getTag()); 203 tag = tagToName(elem->getTag());
205 } else { 204 } else {
206 prio = *msg; 205 prio = *msg;
207 tag = msg + 1; 206 tag = msg + 1;
208 len = strlen(tag);
209 } 207 }
210 if (!__android_log_is_loggable_len(prio, tag, len, ANDROID_LOG_VERBOSE)) { 208 if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
211 // Log traffic received to total 209 // Log traffic received to total
212 pthread_mutex_lock(&mLogElementsLock); 210 pthread_mutex_lock(&mLogElementsLock);
213 stats.add(elem); 211 stats.add(elem);
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 932d55f9a..da63e125e 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -27,6 +27,7 @@
27#include <sysutils/SocketClient.h> 27#include <sysutils/SocketClient.h>
28 28
29#include "LogBufferElement.h" 29#include "LogBufferElement.h"
30#include "LogTags.h"
30#include "LogTimes.h" 31#include "LogTimes.h"
31#include "LogStatistics.h" 32#include "LogStatistics.h"
32#include "LogWhiteBlackList.h" 33#include "LogWhiteBlackList.h"
@@ -99,6 +100,8 @@ class LogBuffer {
99 100
100 bool monotonic; 101 bool monotonic;
101 102
103 LogTags tags;
104
102 LogBufferElement* lastLoggedElements[LOG_ID_MAX]; 105 LogBufferElement* lastLoggedElements[LOG_ID_MAX];
103 LogBufferElement* droppedElements[LOG_ID_MAX]; 106 LogBufferElement* droppedElements[LOG_ID_MAX];
104 void log(LogBufferElement* elem); 107 void log(LogBufferElement* elem);
@@ -133,6 +136,12 @@ public:
133 int initPrune(const char *cp) { return mPrune.init(cp); } 136 int initPrune(const char *cp) { return mPrune.init(cp); }
134 std::string formatPrune() { return mPrune.format(); } 137 std::string formatPrune() { return mPrune.format(); }
135 138
139 std::string formatGetEventTag(uid_t uid,
140 const char *name, const char *format) {
141 return tags.formatGetEventTag(uid, name, format);
142 }
143 const char *tagToName(uint32_t tag) { return tags.tagToName(tag); }
144
136 // helper must be protected directly or implicitly by lock()/unlock() 145 // helper must be protected directly or implicitly by lock()/unlock()
137 const char *pidToName(pid_t pid) { return stats.pidToName(pid); } 146 const char *pidToName(pid_t pid) { return stats.pidToName(pid); }
138 uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); } 147 uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 273150e7d..7e0a6b7e1 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -452,12 +452,11 @@ std::string TagEntry::format(const LogStatistics & /* stat */, log_id_t /* id */
452 name = android::base::StringPrintf("%7u/%u", 452 name = android::base::StringPrintf("%7u/%u",
453 getKey(), uid); 453 getKey(), uid);
454 } 454 }
455 size_t len = 0; 455 const char *nameTmp = getName();
456 const char *nameTmp = getName(len);
457 if (nameTmp) { 456 if (nameTmp) {
458 name += android::base::StringPrintf( 457 name += android::base::StringPrintf(
459 "%*s%.*s", (int)std::max(14 - name.length(), (size_t)1), 458 "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
460 "", (int)len, nameTmp); 459 "", nameTmp);
461 } 460 }
462 461
463 std::string size = android::base::StringPrintf("%zu", 462 std::string size = android::base::StringPrintf("%zu",
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 7acef6d6c..777dc33a5 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -413,7 +413,7 @@ struct TagEntry : public EntryBaseDropped {
413 const uint32_t&getKey() const { return tag; } 413 const uint32_t&getKey() const { return tag; }
414 const pid_t&getPid() const { return pid; } 414 const pid_t&getPid() const { return pid; }
415 const uid_t&getUid() const { return uid; } 415 const uid_t&getUid() const { return uid; }
416 const char*getName(size_t &len) const { return android::tagToName(&len, tag); } 416 const char*getName() const { return android::tagToName(tag); }
417 417
418 inline void add(LogBufferElement *element) { 418 inline void add(LogBufferElement *element) {
419 if (uid != element->getUid()) { 419 if (uid != element->getUid()) {
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
new file mode 100644
index 000000000..a109592ba
--- /dev/null
+++ b/logd/LogTags.cpp
@@ -0,0 +1,884 @@
1/*
2 * Copyright (C) 2017 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 <errno.h>
19#include <fcntl.h>
20#include <inttypes.h>
21#include <pthread.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/mman.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28
29#include <string>
30
31#include <android-base/file.h>
32#include <android-base/macros.h>
33#include <android-base/stringprintf.h>
34#include <log/log_event_list.h>
35#include <private/android_filesystem_config.h>
36#include <private/android_logger.h>
37
38#include "LogTags.h"
39#include "LogUtils.h"
40
41static LogTags* logtags;
42
43const char LogTags::system_event_log_tags[] = "/system/etc/event-log-tags";
44const char LogTags::dynamic_event_log_tags[] = "/dev/event-log-tags";
45// Only for debug
46const char LogTags::debug_event_log_tags[] = "/data/misc/logd/event-log-tags";
47
48// Sniff for first uid=%d in utf8z comment string
49static uid_t sniffUid(const char* comment, const char* endp) {
50 if (!comment) return AID_ROOT;
51
52 if (*comment == '#') ++comment;
53 while ((comment < endp) && (*comment != '\n') && isspace(*comment)) ++comment;
54 static const char uid_str[] = "uid=";
55 if (((comment + strlen(uid_str)) >= endp) ||
56 fastcmp<strncmp>(comment, uid_str, strlen(uid_str)) ||
57 !isdigit(comment[strlen(uid_str)])) return AID_ROOT;
58 char* cp;
59 unsigned long Uid = strtoul(comment + 4, &cp, 10);
60 if ((cp > endp) || (Uid >= INT_MAX)) return AID_ROOT;
61
62 return Uid;
63}
64
65// Checks for file corruption, and report false if there was no need
66// to rebuild the referenced file. Failure to rebuild is only logged,
67// does not cause a return value of false.
68bool LogTags::RebuildFileEventLogTags(const char* filename, bool warn) {
69 int fd;
70
71 {
72 android::RWLock::AutoRLock readLock(rwlock);
73
74 if (tag2total.begin() == tag2total.end()) {
75 return false;
76 }
77
78 file2watermark_const_iterator iwater = file2watermark.find(filename);
79 if (iwater == file2watermark.end()) {
80 return false;
81 }
82
83 struct stat sb;
84 if (!stat(filename, &sb) && ((size_t)sb.st_size >= iwater->second)) {
85 return false;
86 }
87
88 // dump what we already know back into the file?
89 fd = TEMP_FAILURE_RETRY(open(filename,
90 O_WRONLY | O_TRUNC | O_CLOEXEC |
91 O_NOFOLLOW | O_BINARY));
92 if (fd >= 0) {
93 time_t now = time(NULL);
94 struct tm tm;
95 localtime_r(&now, &tm);
96 char timebuf[20];
97 size_t len = strftime(timebuf, sizeof(timebuf),
98 "%Y-%m-%d %H:%M:%S", &tm);
99 android::base::WriteStringToFd(
100 android::base::StringPrintf(
101 "# Rebuilt %.20s, content owned by logd\n", timebuf),
102 fd);
103 for (const auto& it : tag2total) {
104 android::base::WriteStringToFd(formatEntry_locked(it.first,
105 AID_ROOT),
106 fd);
107 }
108 TEMP_FAILURE_RETRY(close(fd));
109 }
110 }
111
112 if (warn) {
113 android::prdebug(((fd < 0) ?
114 "%s failed to rebuild" :
115 "%s missing, damaged or truncated; rebuilt"),
116 filename);
117 }
118
119 if (fd >= 0) {
120 android::RWLock::AutoWLock writeLock(rwlock);
121
122 struct stat sb;
123 if (!stat(filename, &sb)) file2watermark[filename] = sb.st_size;
124 }
125
126 return true;
127}
128
129void LogTags::AddEventLogTags(uint32_t tag, uid_t uid,
130 const std::string& Name,
131 const std::string& Format,
132 const char* source, bool warn) {
133 std::string Key = Name;
134 if (Format.length()) Key += "+" + Format;
135
136 bool update = !source || !!strcmp(source, system_event_log_tags);
137 bool newOne;
138
139 {
140 android::RWLock::AutoWLock writeLock(rwlock);
141
142 tag2total_const_iterator itot = tag2total.find(tag);
143
144 // unlikely except for dupes, or updates to uid list (more later)
145 if (itot != tag2total.end()) update = false;
146
147 newOne = tag2name.find(tag) == tag2name.end();
148 key2tag[Key] = tag;
149
150 if (Format.length()) {
151 if (key2tag.find(Name) == key2tag.end()) {
152 key2tag[Name] = tag;
153 }
154 tag2format[tag] = Format;
155 }
156 tag2name[tag] = Name;
157
158 tag2uid_const_iterator ut = tag2uid.find(tag);
159 if (ut != tag2uid.end()) {
160 if (uid == AID_ROOT) {
161 tag2uid.erase(ut);
162 update = true;
163 } else if (ut->second.find(uid) == ut->second.end()) {
164 const_cast<uid_list&>(ut->second).emplace(uid);
165 update = true;
166 }
167 } else if (newOne && (uid != AID_ROOT)) {
168 tag2uid[tag].emplace(uid);
169 update = true;
170 }
171
172 // updatePersist -> trigger output on modified
173 // content, reset tag2total if available
174 if (update && (itot != tag2total.end())) tag2total[tag] = 0;
175 }
176
177 if (update) {
178 WritePersistEventLogTags(tag, uid, source);
179 } else if (warn && !newOne && source) {
180 // For the files, we want to report dupes.
181 android::prdebug("Multiple tag %" PRIu32 " %s %s %s", tag,
182 Name.c_str(), Format.c_str(), source);
183 }
184}
185
186// Read the event log tags file, and build up our internal database
187void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
188 bool etc = !strcmp(filename, system_event_log_tags);
189 bool debug = !etc && !strcmp(filename, debug_event_log_tags);
190
191 if (!etc) {
192 RebuildFileEventLogTags(filename, warn);
193 }
194 std::string content;
195 if (android::base::ReadFileToString(filename, &content)) {
196 char* cp = (char*) content.c_str();
197 char* endp = cp + content.length();
198
199 {
200 android::RWLock::AutoRLock writeLock(rwlock);
201
202 file2watermark[filename] = content.length();
203 }
204
205 char* lineStart = cp;
206 while (cp < endp) {
207 if (*cp == '\n') {
208 lineStart = cp;
209 } else if (lineStart) {
210 if (*cp == '#') {
211 /* comment; just scan to end */
212 lineStart = NULL;
213 } else if (isdigit(*cp)) {
214 unsigned long Tag = strtoul(cp, &cp, 10);
215 if (warn && (Tag > emptyTag)) {
216 android::prdebug("tag too large %lu", Tag);
217 }
218 while ((cp < endp) && (*cp != '\n') && isspace(*cp)) ++cp;
219 if (cp >= endp) break;
220 if (*cp == '\n') continue;
221 const char* name = cp;
222 /* Determine whether it is a valid tag name [a-zA-Z0-9_] */
223 bool hasAlpha = false;
224 while ((cp < endp) && (isalnum(*cp) || (*cp == '_'))) {
225 if (!isdigit(*cp)) hasAlpha = true;
226 ++cp;
227 }
228 std::string Name(name, cp - name);
229#ifdef ALLOW_NOISY_LOGGING_OF_PROBLEM_WITH_LOTS_OF_TECHNICAL_DEBT
230 static const size_t maximum_official_tag_name_size = 24;
231 if (warn && (Name.length() > maximum_official_tag_name_size)) {
232 android::prdebug("tag name too long %s", Name.c_str());
233 }
234#endif
235 if (hasAlpha && ((cp >= endp) || (*cp == '#') || isspace(*cp))) {
236 if (Tag > emptyTag) {
237 if (*cp != '\n') lineStart = NULL;
238 continue;
239 }
240 while ((cp < endp) && (*cp != '\n') && isspace(*cp)) ++cp;
241 const char* format = cp;
242 uid_t uid = AID_ROOT;
243 while ((cp < endp) && (*cp != '\n')) {
244 if (*cp == '#') {
245 uid = sniffUid(cp, endp);
246 lineStart = NULL;
247 break;
248 }
249 ++cp;
250 }
251 while ((cp > format) && isspace(cp[-1])) {
252 --cp;
253 lineStart = NULL;
254 }
255 std::string Format(format, cp - format);
256
257 AddEventLogTags((uint32_t)Tag, uid, Name, Format,
258 filename, warn);
259 } else {
260 if (warn) {
261 android::prdebug("tag name invalid %.*s",
262 (int)(cp - name + 1), name);
263 }
264 lineStart = NULL;
265 }
266 } else if (!isspace(*cp)) break;
267 }
268 cp++;
269 }
270 } else if (warn) {
271 android::prdebug("Cannot read %s", filename);
272 }
273}
274
275// Extract a 4-byte value from a byte stream.
276static inline uint32_t get4LE(const char* msg)
277{
278 const uint8_t* src = reinterpret_cast<const uint8_t*>(msg);
279 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
280}
281
282// Additional persistent sources for invented log tags. Read the
283// special pmsg event for log tags, and build up our internal
284// database with any found.
285void LogTags::ReadPersistEventLogTags() {
286 struct logger_list* logger_list = android_logger_list_alloc(
287 ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK,
288 0, (pid_t)0);
289 if (!logger_list) return;
290
291 struct logger* e = android_logger_open(logger_list, LOG_ID_EVENTS);
292 struct logger* s = android_logger_open(logger_list, LOG_ID_SECURITY);
293 if (!e && !s) {
294 android_logger_list_free(logger_list);
295 return;
296 }
297
298 for (;;) {
299 struct log_msg log_msg;
300 int ret = android_logger_list_read(logger_list, &log_msg);
301 if (ret <= 0) break;
302
303 const char* msg = log_msg.msg();
304 if (!msg) continue;
305 if (log_msg.entry.len <= sizeof(uint32_t)) continue;
306 uint32_t Tag = get4LE(msg);
307 if (Tag != TAG_DEF_LOG_TAG) continue;
308 uid_t uid = (log_msg.entry.hdr_size >= sizeof(logger_entry_v4)) ?
309 log_msg.entry.uid : AID_ROOT;
310
311 std::string Name;
312 std::string Format;
313 android_log_list_element elem;
314 {
315 android_log_event_list ctx(log_msg);
316 elem = ctx.read();
317 if (elem.type != EVENT_TYPE_LIST) {
318 continue;
319 }
320 elem = ctx.read();
321 if (elem.type != EVENT_TYPE_INT) {
322 continue;
323 }
324 Tag = elem.data.int32;
325 elem = ctx.read();
326 if (elem.type != EVENT_TYPE_STRING) {
327 continue;
328 }
329 Name = std::string(elem.data.string, elem.len);
330 elem = ctx.read();
331 if (elem.type != EVENT_TYPE_STRING) {
332 continue;
333 }
334 Format = std::string(elem.data.string, elem.len);
335 elem = ctx.read();
336 }
337 if ((elem.type != EVENT_TYPE_LIST_STOP) || !elem.complete) continue;
338
339 AddEventLogTags(Tag, uid, Name, Format);
340 }
341 android_logger_list_free(logger_list);
342}
343
344LogTags::LogTags() {
345 ReadFileEventLogTags(system_event_log_tags);
346 // Following will likely fail on boot, but is required if logd restarts
347 ReadFileEventLogTags(dynamic_event_log_tags, false);
348 if (__android_log_is_debuggable()) {
349 ReadFileEventLogTags(debug_event_log_tags, false);
350 }
351 ReadPersistEventLogTags();
352
353 logtags = this;
354}
355
356// Converts an event tag into a name
357const char* LogTags::tagToName(uint32_t tag) const {
358 tag2name_const_iterator it;
359
360 android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
361
362 it = tag2name.find(tag);
363 if ((it == tag2name.end()) || (it->second.length() == 0)) return NULL;
364
365 return it->second.c_str();
366}
367
368// Prototype in LogUtils.h allowing external access to our database.
369//
370// This must be a pure reader to our database, as everything else is
371// guaranteed single-threaded except this access point which is
372// asynchonous and can be multithreaded and thus rentrant. The
373// object's rwlock is only used to guarantee atomic access to the
374// unordered_map to prevent corruption, with a requirement to be a
375// low chance of contention for this call. If we end up changing
376// this algorithm resulting in write, then we should use a different
377// lock than the object's rwlock to protect groups of associated
378// actions.
379const char* android::tagToName(uint32_t tag) {
380 LogTags* me = logtags;
381
382 if (!me) return NULL;
383 me->WritePmsgEventLogTags(tag);
384 return me->tagToName(tag);
385}
386
387// Prototype in LogUtils.h allowing external access to our database.
388//
389// This only works on userdebug and eng devices to re-read the
390// /data/misc/logd/event-log-tags file right after /data is mounted.
391// The operation is near to boot and should only happen once. There
392// are races associated with its use since it can trigger a Rebuild
393// of the file, but that is a can-not-happen since the file was not
394// read yet. More dangerous if called later, but if all is well it
395// should just skip over everything and not write any new entries.
396void android::ReReadEventLogTags() {
397 LogTags* me = logtags;
398
399 if (me && __android_log_is_debuggable()) {
400 me->ReadFileEventLogTags(me->debug_event_log_tags);
401 }
402}
403
404// converts an event tag into a format
405const char* LogTags::tagToFormat(uint32_t tag) const {
406 tag2format_const_iterator iform;
407
408 android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
409
410 iform = tag2format.find(tag);
411 if (iform == tag2format.end()) return NULL;
412
413 return iform->second.c_str();
414}
415
416// converts a name into an event tag
417uint32_t LogTags::nameToTag(const char* name) const {
418 uint32_t ret = emptyTag;
419
420 // Bug: Only works for a single entry, we can have multiple entries,
421 // one for each format, so we find first entry recorded, or entry with
422 // no format associated with it.
423
424 android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
425
426 key2tag_const_iterator ik = key2tag.find(std::string(name));
427 if (ik != key2tag.end()) ret = ik->second;
428
429 return ret;
430}
431
432// Caller must perform locks, can be under reader (for pre-check) or
433// writer lock. We use this call to invent a new deterministically
434// random tag, unique is cleared if no conflicts. If format is NULL,
435// we are in readonly mode.
436uint32_t LogTags::nameToTag_locked(const std::string& name,
437 const char* format,
438 bool& unique) {
439 key2tag_const_iterator ik;
440
441 bool write = format != NULL;
442 unique = write;
443
444 if (!write) {
445 // Bug: Only works for a single entry, we can have multiple entries,
446 // one for each format, so we find first entry recorded, or entry with
447 // no format associated with it.
448 ik = key2tag.find(name);
449 if (ik == key2tag.end()) return emptyTag;
450 return ik->second;
451 }
452
453 std::string Key(name);
454 if (*format) Key += std::string("+") + format;
455
456 ik = key2tag.find(Key);
457 if (ik != key2tag.end()) {
458 unique = false;
459 return ik->second;
460 }
461
462 size_t Hash = key2tag.hash_function()(Key);
463 uint32_t Tag = Hash;
464 // This sets an upper limit on the conflics we are allowed to deal with.
465 for (unsigned i = 0; i < 256; ) {
466 tag2name_const_iterator it = tag2name.find(Tag);
467 if (it == tag2name.end()) return Tag;
468 std::string localKey(it->second);
469 tag2format_const_iterator iform = tag2format.find(Tag);
470 if ((iform == tag2format.end()) && iform->second.length()) {
471 localKey += "+" + iform->second;
472 }
473 unique = !!it->second.compare(localKey);
474 if (!unique) return Tag; // unlikely except in a race
475
476 ++i;
477 // Algorithm to convert hash to next tag
478 if (i < 32) {
479 Tag = (Hash >> i);
480 // size_t is 32 bits, or upper word zero, rotate
481 if ((sizeof(Hash) <= 4) ||
482 ((Hash & (uint64_t(-1LL) << 32)) == 0)) {
483 Tag |= Hash << (32 - i);
484 }
485 } else {
486 Tag = Hash + i - 31;
487 }
488 }
489 return emptyTag;
490}
491
492static int openFile(const char* name, int mode, bool warning) {
493 int fd = TEMP_FAILURE_RETRY(open(name, mode));
494 if ((fd < 0) && warning) {
495 android::prdebug("Failed open %s (%d)", name, errno);
496 }
497 return fd;
498}
499
500void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
501 android::RWLock::AutoRLock readLock(rwlock);
502
503 tag2total_const_iterator itot = tag2total.find(tag);
504 if (itot == tag2total.end()) return; // source is a static entry
505
506 size_t lastTotal = itot->second;
507
508 // Every 16K (half the smallest configurable pmsg buffer size) record
509 static const size_t rate_to_pmsg = 16 * 1024;
510 if (lastTotal && ((android::sizesTotal() - lastTotal) < rate_to_pmsg)) {
511 return;
512 }
513
514 static int pmsg_fd = -1;
515 if (pmsg_fd < 0) {
516 pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
517 // unlikely, but deal with partners with borken pmsg
518 if (pmsg_fd < 0) return;
519 }
520
521 std::string Name = tag2name[tag];
522 tag2format_const_iterator iform = tag2format.find(tag);
523 std::string Format = (iform != tag2format.end()) ? iform->second : "";
524
525 __android_log_event_list ctx(TAG_DEF_LOG_TAG);
526 ctx << tag << Name << Format;
527 std::string buffer(ctx);
528 if (buffer.length() <= 0) return; // unlikely
529
530 /*
531 * struct {
532 * // what we provide to pstore
533 * android_pmsg_log_header_t pmsgHeader;
534 * // what we provide to file
535 * android_log_header_t header;
536 * // caller provides
537 * union {
538 * struct {
539 * char prio;
540 * char payload[];
541 * } string;
542 * struct {
543 * uint32_t tag
544 * char payload[];
545 * } binary;
546 * };
547 * };
548 */
549
550 struct timespec ts;
551 clock_gettime(android_log_clockid(), &ts);
552
553 android_log_header_t header = {
554 .id = LOG_ID_EVENTS,
555 .tid = (uint16_t)gettid(),
556 .realtime.tv_sec = (uint32_t)ts.tv_sec,
557 .realtime.tv_nsec = (uint32_t)ts.tv_nsec,
558 };
559
560 uint32_t outTag = TAG_DEF_LOG_TAG;
561 outTag = get4LE((const char*)&outTag);
562
563 android_pmsg_log_header_t pmsgHeader = {
564 .magic = LOGGER_MAGIC,
565 .len = (uint16_t)(sizeof(pmsgHeader) + sizeof(header) +
566 sizeof(outTag) + buffer.length()),
567 .uid = (uint16_t)AID_ROOT,
568 .pid = (uint16_t)getpid(),
569 };
570
571 struct iovec Vec[] = {
572 { (unsigned char*)&pmsgHeader, sizeof(pmsgHeader) },
573 { (unsigned char*)&header, sizeof(header) },
574 { (unsigned char*)&outTag, sizeof(outTag) },
575 { (unsigned char*)const_cast<char*>(buffer.data()), buffer.length() }
576 };
577
578 tag2uid_const_iterator ut = tag2uid.find(tag);
579 if (ut == tag2uid.end()) {
580 TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
581 } else if (uid != AID_ROOT) {
582 pmsgHeader.uid = (uint16_t)uid;
583 TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
584 } else {
585 for (auto &it : ut->second) {
586 pmsgHeader.uid = (uint16_t)it;
587 TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
588 }
589 }
590}
591
592void LogTags::WriteDynamicEventLogTags(uint32_t tag, uid_t uid) {
593 static const int mode = O_WRONLY | O_APPEND |
594 O_CLOEXEC | O_NOFOLLOW | O_BINARY;
595
596 int fd = openFile(dynamic_event_log_tags, mode, true);
597 if (fd < 0) return;
598
599 android::RWLock::AutoWLock writeLock(rwlock);
600
601 std::string ret = formatEntry_locked(tag, uid, false);
602 android::base::WriteStringToFd(ret, fd);
603 TEMP_FAILURE_RETRY(close(fd));
604
605 size_t size = 0;
606 file2watermark_const_iterator iwater;
607
608 iwater = file2watermark.find(dynamic_event_log_tags);
609 if (iwater != file2watermark.end()) size = iwater->second;
610
611 file2watermark[dynamic_event_log_tags] = size + ret.length();
612}
613
614void LogTags::WriteDebugEventLogTags(uint32_t tag, uid_t uid) {
615 static const int mode = O_WRONLY | O_APPEND |
616 O_CLOEXEC | O_NOFOLLOW | O_BINARY;
617
618 static bool one = true;
619 int fd = openFile(debug_event_log_tags, mode, one);
620 one = fd >= 0;
621 if (!one) return;
622
623 android::RWLock::AutoWLock writeLock(rwlock);
624
625 std::string ret = formatEntry_locked(tag, uid, false);
626 android::base::WriteStringToFd(ret, fd);
627 TEMP_FAILURE_RETRY(close(fd));
628
629 size_t size = 0;
630 file2watermark_const_iterator iwater;
631
632 iwater = file2watermark.find(debug_event_log_tags);
633 if (iwater != file2watermark.end()) size = iwater->second;
634
635 file2watermark[debug_event_log_tags] = size + ret.length();
636}
637
638// How we maintain some runtime or reboot stickiness
639void LogTags::WritePersistEventLogTags(uint32_t tag,
640 uid_t uid, const char* source) {
641 // very unlikely
642 bool etc = source && !strcmp(source, system_event_log_tags);
643 if (etc) return;
644
645 bool dynamic = source && !strcmp(source, dynamic_event_log_tags);
646 bool debug = (!dynamic &&
647 source &&
648 !strcmp(source, debug_event_log_tags)) ||
649 !__android_log_is_debuggable();
650
651 WritePmsgEventLogTags(tag, uid);
652
653 size_t lastTotal = 0;
654 {
655 android::RWLock::AutoRLock readLock(rwlock);
656
657 tag2total_const_iterator itot = tag2total.find(tag);
658 if (itot != tag2total.end()) lastTotal = itot->second;
659 }
660
661 if (lastTotal == 0) { // denotes first time for this one
662 if (!dynamic || !RebuildFileEventLogTags(dynamic_event_log_tags)) {
663 WriteDynamicEventLogTags(tag, uid);
664 }
665
666 if (!debug && !RebuildFileEventLogTags(debug_event_log_tags)) {
667 WriteDebugEventLogTags(tag, uid);
668 }
669 }
670
671 lastTotal = android::sizesTotal();
672 if (!lastTotal) ++lastTotal;
673
674 // record totals for next watermark.
675 android::RWLock::AutoWLock writeLock(rwlock);
676 tag2total[tag] = lastTotal;
677}
678
679// nameToTag converts a name into an event tag. If format is NULL, then we
680// are in readonly mode.
681uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
682 std::string Name = std::string(name);
683 bool write = format != NULL;
684 bool updateUid = uid != AID_ROOT;
685 bool updateFormat = format && *format;
686 bool unique;
687 uint32_t Tag;
688
689 {
690 android::RWLock::AutoRLock readLock(rwlock);
691
692 Tag = nameToTag_locked(Name, format, unique);
693 if (updateUid && (Tag != emptyTag) && !unique) {
694 tag2uid_const_iterator ut = tag2uid.find(Tag);
695 if (updateUid) {
696 if ((ut != tag2uid.end()) &&
697 (ut->second.find(uid) == ut->second.end())) {
698 unique = write; // write passthrough to update uid counts
699 if (!write) Tag = emptyTag; // deny read access
700 }
701 } else {
702 unique = write && (ut != tag2uid.end());
703 }
704 }
705 }
706
707 if (Tag == emptyTag) return Tag;
708 WritePmsgEventLogTags(Tag, uid); // record references periodically
709 if (!unique) return Tag;
710
711 bool updateWrite = false;
712 bool updateTag;
713
714 // Special case of AddEventLogTags, checks per-uid counter which makes
715 // no sense there, and is also optimized somewhat to reduce write times.
716 {
717 android::RWLock::AutoWLock writeLock(rwlock);
718
719 // double check after switch from read lock to write lock for Tag
720 updateTag = tag2name.find(Tag) == tag2name.end();
721 // unlikely, either update, race inviting conflict or multiple uids
722 if (!updateTag) {
723 Tag = nameToTag_locked(Name, format, unique);
724 if (Tag == emptyTag) return Tag;
725 // is it multiple uid's setting this value
726 if (!unique) {
727 tag2uid_const_iterator ut = tag2uid.find(Tag);
728 if (updateUid) {
729 // Add it to the uid list
730 if ((ut == tag2uid.end()) ||
731 (ut->second.find(uid) != ut->second.end())) return Tag;
732 const_cast<uid_list&>(ut->second).emplace(uid);
733 updateWrite = true;
734 } else {
735 if (ut == tag2uid.end()) return Tag;
736 // (system) adding a global one, erase the uid list
737 tag2uid.erase(ut);
738 updateWrite = true;
739 }
740 }
741 }
742
743 // Update section
744 size_t count;
745 if (updateUid) {
746 count = 0;
747 uid2count_const_iterator ci = uid2count.find(uid);
748 if (ci != uid2count.end()) {
749 count = ci->second;
750 if (count >= max_per_uid) {
751 if (!updateWrite) return emptyTag;
752 // If we are added to the per-Uid perms, leak the Tag
753 // if it already exists.
754 updateUid = false;
755 updateTag = false;
756 updateFormat = false;
757 }
758 }
759 }
760
761 // updateWrite -> trigger output on modified content, reset tag2total
762 // also sets static to dynamic entries if they are alterred,
763 // only occurs if they have a uid, and runtime adds another uid.
764 if (updateWrite) tag2total[Tag] = 0;
765
766 if (updateTag) {
767 // mark as a dynamic entry, but do not upset current total counter
768 tag2total_const_iterator itot = tag2total.find(Tag);
769 if (itot == tag2total.end()) tag2total[Tag] = 0;
770
771 if (*format) {
772 key2tag[Name + "+" + format] = Tag;
773 if (key2tag.find(Name) == key2tag.end()) key2tag[Name] = Tag;
774 } else {
775 key2tag[Name] = Tag;
776 }
777 tag2name[Tag] = Name;
778 }
779 if (updateFormat) tag2format[Tag] = format;
780
781 if (updateUid) {
782 tag2uid[Tag].emplace(uid);
783 uid2count[uid] = count + 1;
784 }
785 }
786
787 if (updateTag || updateFormat || updateWrite) {
788 WritePersistEventLogTags(Tag, uid);
789 }
790
791 return Tag;
792}
793
794std::string LogTags::formatEntry(uint32_t tag, uid_t uid,
795 const char* name,
796 const char* format) {
797 if (!format || !format[0]) {
798 return android::base::StringPrintf("%" PRIu32 "\t%s\n", tag, name);
799 }
800 size_t len = (strlen(name) + 7) / 8;
801 static const char tabs[] = "\t\t\t";
802 if (len > strlen(tabs)) len = strlen(tabs);
803 std::string Uid;
804 if (uid != AID_ROOT) Uid = android::base::StringPrintf(" # uid=%u", uid);
805 return android::base::StringPrintf("%" PRIu32 "\t%s%s\t%s%s\n",
806 tag, name, &tabs[len], format,
807 Uid.c_str());
808}
809
810std::string LogTags::formatEntry_locked(uint32_t tag, uid_t uid,
811 bool authenticate) {
812 const char* name = tag2name[tag].c_str();
813
814 const char* format = "";
815 tag2format_const_iterator iform = tag2format.find(tag);
816 if (iform != tag2format.end()) format = iform->second.c_str();
817
818 // Access permission test, do not report dynamic entries
819 // that do not belong to us.
820 tag2uid_const_iterator ut = tag2uid.find(tag);
821 if (ut == tag2uid.end()) {
822 return formatEntry(tag, AID_ROOT, name, format);
823 }
824 if (uid != AID_ROOT) {
825 if (authenticate && (ut->second.find(uid) == ut->second.end())) {
826 return std::string("");
827 }
828 return formatEntry(tag, uid, name, format);
829 }
830
831 // Show all, one for each registered uid (we are group root)
832 std::string ret;
833 for (auto &it : ut->second) {
834 ret += formatEntry(tag, it, name, format);
835 }
836 return ret;
837}
838
839std::string LogTags::formatGetEventTag(uid_t uid,
840 const char* name, const char* format) {
841 bool all = name && (name[0] == '*') && !name[1];
842 bool list = !name || all;
843 std::string ret;
844
845 if (!list) {
846 // switch to read entry only if format == "*"
847 if (format && (format[0] == '*') && !format[1]) format = NULL;
848
849 // WAI: for null format, only works for a single entry, we can have
850 // multiple entries, one for each format, so we find first entry
851 // recorded, or entry with no format associated with it.
852 // We may desire to print all that match the name, but we did not
853 // add a mapping table for that and the cost is too high.
854 uint32_t tag = nameToTag(uid, name, format);
855 if (tag == emptyTag) return std::string("-1 ESRCH");
856 if (uid == AID_ROOT) {
857 android::RWLock::AutoRLock readLock(rwlock);
858
859 // first uid in list so as to manufacture an accurate reference
860 tag2uid_const_iterator ut = tag2uid.find(tag);
861 if ((ut != tag2uid.end()) &&
862 (ut->second.begin() != ut->second.end())) {
863 uid = *(ut->second.begin());
864 }
865 }
866 ret = formatEntry(tag, uid, name, format ?: tagToFormat(tag));
867 if (!ret.length()) return std::string("-1 ESRCH");
868 return ret;
869 }
870
871 android::RWLock::AutoRLock readLock(rwlock);
872 if (all) {
873 // everything under the sun
874 for (const auto& it : tag2name) {
875 ret += formatEntry_locked(it.first, uid);
876 }
877 } else {
878 // set entries are dynamic
879 for (const auto& it : tag2total) {
880 ret += formatEntry_locked(it.first, uid);
881 }
882 }
883 return ret;
884}
diff --git a/logd/LogTags.h b/logd/LogTags.h
new file mode 100644
index 000000000..37a6d9632
--- /dev/null
+++ b/logd/LogTags.h
@@ -0,0 +1,118 @@
1/*
2 * Copyright (C) 2017 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#ifndef _LOGD_LOG_TAGS_H__
18#define _LOGD_LOG_TAGS_H__
19
20#include <unordered_map>
21#include <unordered_set>
22#include <string>
23
24#include <utils/RWLock.h>
25
26class LogTags {
27 // This lock protects all the unordered_map accesses below. It
28 // is a reader/writer lock so that contentions are kept to a
29 // minimum since writes are rare, even administratably when
30 // reads are extended. Resist the temptation to use the writer
31 // lock to protect anything outside the following unordered_maps
32 // as that would increase the reader contentions. Use a separate
33 // mutex to protect the other entities.
34 android::RWLock rwlock;
35
36 // key is Name + "+" + Format
37 std::unordered_map<std::string, uint32_t> key2tag;
38 typedef std::unordered_map<std::string, uint32_t>::const_iterator key2tag_const_iterator;
39
40 // Allows us to manage access permissions based on uid registrants
41 // Global entries are specifically erased.
42 typedef std::unordered_set<uid_t> uid_list;
43 std::unordered_map<uint32_t, uid_list> tag2uid;
44 typedef std::unordered_map<uint32_t, uid_list>::const_iterator tag2uid_const_iterator;
45
46 std::unordered_map<uint32_t, std::string> tag2name;
47 typedef std::unordered_map<uint32_t, std::string>::const_iterator tag2name_const_iterator;
48
49 std::unordered_map<uint32_t, std::string> tag2format;
50 typedef std::unordered_map<uint32_t, std::string>::const_iterator tag2format_const_iterator;
51
52 static const size_t max_per_uid = 256; // Put a cap on the tags per uid
53 std::unordered_map<uid_t, size_t> uid2count;
54 typedef std::unordered_map<uid_t, size_t>::const_iterator uid2count_const_iterator;
55
56 // Dynamic entries are assigned
57 std::unordered_map<uint32_t, size_t> tag2total;
58 typedef std::unordered_map<uint32_t, size_t>::const_iterator tag2total_const_iterator;
59
60 // emplace unique tag
61 uint32_t nameToTag(uid_t uid, const char* name, const char* format);
62 // find unique or associated tag
63 uint32_t nameToTag_locked(const std::string& name, const char* format, bool &unique);
64
65 // Record expected file watermarks to detect corruption.
66 std::unordered_map<std::string, size_t> file2watermark;
67 typedef std::unordered_map<std::string, size_t>::const_iterator file2watermark_const_iterator;
68
69 void ReadPersistEventLogTags();
70
71 // format helpers
72 // format a single entry, does not need object data
73 static std::string formatEntry(uint32_t tag, uid_t uid,
74 const char* name, const char* format);
75 // caller locks, database lookup, authenticate against uid
76 std::string formatEntry_locked(uint32_t tag, uid_t uid,
77 bool authenticate = true);
78
79 bool RebuildFileEventLogTags(const char* filename, bool warn = true);
80
81 void AddEventLogTags(uint32_t tag, uid_t uid,
82 const std::string& Name, const std::string& Format,
83 const char* source = NULL, bool warn = false);
84
85 void WriteDynamicEventLogTags(uint32_t tag, uid_t uid);
86 void WriteDebugEventLogTags(uint32_t tag, uid_t uid);
87 // push tag details to persistent storage
88 void WritePersistEventLogTags(uint32_t tag,
89 uid_t uid = AID_ROOT,
90 const char* source = NULL);
91
92 static const uint32_t emptyTag = uint32_t(-1);
93
94public:
95
96 static const char system_event_log_tags[];
97 static const char dynamic_event_log_tags[];
98 // Only for userdebug and eng
99 static const char debug_event_log_tags[];
100
101 LogTags();
102
103 void WritePmsgEventLogTags(uint32_t tag, uid_t uid = AID_ROOT);
104 void ReadFileEventLogTags(const char* filename, bool warn = true);
105
106 // reverse lookup from tag
107 const char* tagToName(uint32_t tag) const;
108 const char* tagToFormat(uint32_t tag) const;
109 // find associated tag
110 uint32_t nameToTag(const char* name) const;
111
112 // emplace tag if necessary, provide event-log-tag formated output in string
113 std::string formatGetEventTag(uid_t uid,
114 const char* name,
115 const char* format);
116};
117
118#endif // _LOGD_LOG_TAGS_H__
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 70f24e4d9..f044b2744 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -39,8 +39,9 @@ size_t sizesTotal();
39char *pidToName(pid_t pid); 39char *pidToName(pid_t pid);
40char *tidToName(pid_t tid); 40char *tidToName(pid_t tid);
41 41
42// Furnished in main.cpp. Thread safe. 42// Furnished in LogTags.cpp. Thread safe.
43const char *tagToName(size_t *len, uint32_t tag); 43const char *tagToName(uint32_t tag);
44void ReReadEventLogTags();
44 45
45// Furnished by LogKlog.cpp. 46// Furnished by LogKlog.cpp.
46const char* strnstr(const char* s, size_t len, const char* needle); 47const char* strnstr(const char* s, size_t len, const char* needle);
diff --git a/logd/event.logtags b/logd/event.logtags
index 0d24df0cb..39063a982 100644
--- a/logd/event.logtags
+++ b/logd/event.logtags
@@ -35,3 +35,4 @@
35 35
361003 auditd (avc|3) 361003 auditd (avc|3)
371004 chatty (dropped|3) 371004 chatty (dropped|3)
381005 tag_def (tag|1),(name|3),(format|3)
diff --git a/logd/logd.rc b/logd/logd.rc
index 54349dd67..ee89b83b5 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -14,3 +14,10 @@ service logd-reinit /system/bin/logd --reinit
14 user logd 14 user logd
15 group logd 15 group logd
16 writepid /dev/cpuset/system-background/tasks 16 writepid /dev/cpuset/system-background/tasks
17
18on fs
19 write /dev/event-log-tags "# content owned by logd
20"
21 chown logd logd /dev/event-log-tags
22 chmod 0644 /dev/event-log-tags
23 restorecon /dev/event-log-tags
diff --git a/logd/logtagd.rc b/logd/logtagd.rc
new file mode 100644
index 000000000..46aa8c1d9
--- /dev/null
+++ b/logd/logtagd.rc
@@ -0,0 +1,9 @@
1#
2# logtagd event log tag service (debug only)
3#
4on post-fs-data
5 mkdir /data/misc/logd 0700 logd log
6 write /data/misc/logd/event-log-tags ""
7 chown logd log /data/misc/logd/event-log-tags
8 chmod 0600 /data/misc/logd/event-log-tags
9 restorecon /data/misc/logd/event-log-tags
diff --git a/logd/main.cpp b/logd/main.cpp
index 5878f151e..2551f2e9b 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -244,7 +244,7 @@ static void *reinit_thread_start(void * /*obj*/) {
244 // anything else, we have even lesser privileges and accept our fate. Not 244 // anything else, we have even lesser privileges and accept our fate. Not
245 // worth checking for error returns setting this thread's privileges. 245 // worth checking for error returns setting this thread's privileges.
246 (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list 246 (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
247 (void)setuid(AID_LOGD); // access to everything logd. 247 (void)setuid(AID_LOGD); // access to everything logd, eg /data/misc/logd
248 248
249 while (reinit_running && !sem_wait(&reinit) && reinit_running) { 249 while (reinit_running && !sem_wait(&reinit) && reinit_running) {
250 250
@@ -271,6 +271,7 @@ static void *reinit_thread_start(void * /*obj*/) {
271 logBuf->init(); 271 logBuf->init();
272 logBuf->initPrune(NULL); 272 logBuf->initPrune(NULL);
273 } 273 }
274 android::ReReadEventLogTags();
274 } 275 }
275 276
276 return NULL; 277 return NULL;
@@ -304,24 +305,6 @@ void reinit_signal_handler(int /*signal*/) {
304 sem_post(&reinit); 305 sem_post(&reinit);
305} 306}
306 307
307// tagToName converts an events tag into a name
308const char *android::tagToName(size_t *len, uint32_t tag) {
309 static const EventTagMap *map;
310
311 if (!map) {
312 sem_wait(&sem_name);
313 if (!map) {
314 map = android_openEventTagMap(NULL);
315 }
316 sem_post(&sem_name);
317 if (!map) {
318 if (len) len = 0;
319 return NULL;
320 }
321 }
322 return android_lookupEventTag_len(map, len, tag);
323}
324
325static void readDmesg(LogAudit *al, LogKlog *kl) { 308static void readDmesg(LogAudit *al, LogKlog *kl) {
326 if (!al && !kl) { 309 if (!al && !kl) {
327 return; 310 return;
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 2a6cdc8f5..0db33b755 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -39,12 +39,8 @@
39#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_* 39#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
40#include "../LogReader.h" // pickup LOGD_SNDTIMEO 40#include "../LogReader.h" // pickup LOGD_SNDTIMEO
41 41
42/* 42static void send_to_control(char* buf, size_t len)
43 * returns statistics
44 */
45static void my_android_logger_get_statistics(char *buf, size_t len)
46{ 43{
47 snprintf(buf, len, "getStatistics 0 1 2 3 4");
48 int sock = socket_local_client("logd", 44 int sock = socket_local_client("logd",
49 ANDROID_SOCKET_NAMESPACE_RESERVED, 45 ANDROID_SOCKET_NAMESPACE_RESERVED,
50 SOCK_STREAM); 46 SOCK_STREAM);
@@ -74,6 +70,15 @@ static void my_android_logger_get_statistics(char *buf, size_t len)
74 } 70 }
75} 71}
76 72
73/*
74 * returns statistics
75 */
76static void my_android_logger_get_statistics(char *buf, size_t len)
77{
78 snprintf(buf, len, "getStatistics 0 1 2 3 4");
79 send_to_control(buf, len);
80}
81
77static void alloc_statistics(char **buffer, size_t *length) 82static void alloc_statistics(char **buffer, size_t *length)
78{ 83{
79 size_t len = 8192; 84 size_t len = 8192;
@@ -816,6 +821,44 @@ TEST(logd, SNDTIMEO) {
816 close(fd); 821 close(fd);
817} 822}
818 823
824TEST(logd, getEventTag_list) {
825#ifdef __ANDROID__
826 char buffer[256];
827 memset(buffer, 0, sizeof(buffer));
828 snprintf(buffer, sizeof(buffer), "getEventTag name=*");
829 send_to_control(buffer, sizeof(buffer));
830 buffer[sizeof(buffer) - 1] = '\0';
831 char *cp;
832 long ret = strtol(buffer, &cp, 10);
833 EXPECT_GT(ret, 4096);
834#else
835 GTEST_LOG_(INFO) << "This test does nothing.\n";
836#endif
837}
838
839TEST(logd, getEventTag_newentry) {
840#ifdef __ANDROID__
841 char buffer[256];
842 memset(buffer, 0, sizeof(buffer));
843 log_time now(CLOCK_MONOTONIC);
844 char name[64];
845 snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
846 snprintf(buffer, sizeof(buffer),
847 "getEventTag name=%s format=\"(new|1)\"", name);
848 send_to_control(buffer, sizeof(buffer));
849 buffer[sizeof(buffer) - 1] = '\0';
850 char *cp;
851 long ret = strtol(buffer, &cp, 10);
852 EXPECT_GT(ret, 16);
853 EXPECT_TRUE(strstr(buffer, "\t(new|1)") != NULL);
854 EXPECT_TRUE(strstr(buffer, name) != NULL);
855 // ToDo: also look for this in /data/misc/logd/event-log-tags and
856 // /dev/event-log-tags.
857#else
858 GTEST_LOG_(INFO) << "This test does nothing.\n";
859#endif
860}
861
819static inline int32_t get4LE(const char* src) 862static inline int32_t get4LE(const char* src)
820{ 863{
821 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); 864 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);