1 /*
2 * Copyright (C) 2012-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 "LogBufferElement.h"
18
19 #include <ctype.h>
20 #include <endian.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26
27 #include <log/log_read.h>
28 #include <private/android_logger.h>
29
30 #include "LogStatistics.h"
31 #include "LogUtils.h"
32
LogBufferElement(log_id_t log_id,log_time realtime,uid_t uid,pid_t pid,pid_t tid,uint64_t sequence,const char * msg,uint16_t len)33 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
34 pid_t tid, uint64_t sequence, const char* msg, uint16_t len)
35 : uid_(uid),
36 pid_(pid),
37 tid_(tid),
38 sequence_(sequence),
39 realtime_(realtime),
40 msg_len_(len),
41 log_id_(log_id) {
42 msg_ = new char[len];
43 memcpy(msg_, msg, len);
44 }
45
LogBufferElement(const LogBufferElement & elem)46 LogBufferElement::LogBufferElement(const LogBufferElement& elem)
47 : uid_(elem.uid_),
48 pid_(elem.pid_),
49 tid_(elem.tid_),
50 sequence_(elem.sequence_),
51 realtime_(elem.realtime_),
52 msg_len_(elem.msg_len_),
53 log_id_(elem.log_id_) {
54 msg_ = new char[msg_len_];
55 memcpy(msg_, elem.msg_, msg_len_);
56 }
57
LogBufferElement(LogBufferElement && elem)58 LogBufferElement::LogBufferElement(LogBufferElement&& elem) noexcept
59 : uid_(elem.uid_),
60 pid_(elem.pid_),
61 tid_(elem.tid_),
62 sequence_(elem.sequence_),
63 realtime_(elem.realtime_),
64 msg_len_(elem.msg_len_),
65 log_id_(elem.log_id_) {
66 msg_ = elem.msg_;
67 elem.msg_ = nullptr;
68 }
69
~LogBufferElement()70 LogBufferElement::~LogBufferElement() {
71 delete[] msg_;
72 }
73
GetTag() const74 uint32_t LogBufferElement::GetTag() const {
75 // Binary buffers have no tag.
76 if (!IsBinary(log_id())) {
77 return 0;
78 }
79 return MsgToTag(msg(), msg_len());
80 }
81
ToLogStatisticsElement() const82 LogStatisticsElement LogBufferElement::ToLogStatisticsElement() const {
83 // Estimate the size of this element in the parent std::list<> by adding two void*'s
84 // corresponding to the next/prev pointers and aligning to 64 bit.
85 uint16_t element_in_list_size =
86 (sizeof(*this) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) & -sizeof(uint64_t);
87 return LogStatisticsElement{
88 .uid = uid(),
89 .pid = pid(),
90 .tid = tid(),
91 .tag = GetTag(),
92 .realtime = realtime(),
93 .msg = msg(),
94 .msg_len = msg_len(),
95 .log_id = log_id(),
96 .total_len = static_cast<uint16_t>(element_in_list_size + msg_len()),
97 };
98 }
99
100 // caller must own and free character string
tidToName(pid_t tid)101 char* android::tidToName(pid_t tid) {
102 char* retval = nullptr;
103 char buffer[256];
104 snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
105 int fd = open(buffer, O_RDONLY | O_CLOEXEC);
106 if (fd >= 0) {
107 ssize_t ret = read(fd, buffer, sizeof(buffer));
108 if (ret >= (ssize_t)sizeof(buffer)) {
109 ret = sizeof(buffer) - 1;
110 }
111 while ((ret > 0) && isspace(buffer[ret - 1])) {
112 --ret;
113 }
114 if (ret > 0) {
115 buffer[ret] = '\0';
116 retval = strdup(buffer);
117 }
118 close(fd);
119 }
120
121 // if nothing for comm, check out cmdline
122 char* name = android::pidToName(tid);
123 if (!retval) {
124 retval = name;
125 name = nullptr;
126 }
127
128 // check if comm is truncated, see if cmdline has full representation
129 if (name) {
130 // impossible for retval to be NULL if name not NULL
131 size_t retval_len = strlen(retval);
132 size_t name_len = strlen(name);
133 // KISS: ToDo: Only checks prefix truncated, not suffix, or both
134 if ((retval_len < name_len) &&
135 !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
136 free(retval);
137 retval = name;
138 } else {
139 free(name);
140 }
141 }
142 return retval;
143 }
144
FlushTo(LogWriter * writer)145 bool LogBufferElement::FlushTo(LogWriter* writer) {
146 struct logger_entry entry = {};
147
148 entry.hdr_size = sizeof(struct logger_entry);
149 entry.lid = log_id_;
150 entry.pid = pid_;
151 entry.tid = tid_;
152 entry.uid = uid_;
153 entry.sec = realtime_.tv_sec;
154 entry.nsec = realtime_.tv_nsec;
155 entry.len = msg_len_;
156
157 return writer->Write(entry, msg_);
158 }
159