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 <ctype.h>
18 #include <endian.h>
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
23 #include <unistd.h>
24 
25 #include <log/logger.h>
26 #include <private/android_logger.h>
27 
28 #include "LogBufferElement.h"
29 #include "LogCommand.h"
30 #include "LogReader.h"
31 
32 const uint64_t LogBufferElement::FLUSH_ERROR(0);
33 atomic_int_fast64_t LogBufferElement::sequence(1);
34 
LogBufferElement(log_id_t log_id,log_time realtime,uid_t uid,pid_t pid,pid_t tid,const char * msg,unsigned short len)35 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
36                                    uid_t uid, pid_t pid, pid_t tid,
37                                    const char *msg, unsigned short len) :
38         mLogId(log_id),
39         mUid(uid),
40         mPid(pid),
41         mTid(tid),
42         mMsgLen(len),
43         mSequence(sequence.fetch_add(1, memory_order_relaxed)),
44         mRealTime(realtime) {
45     mMsg = new char[len];
46     memcpy(mMsg, msg, len);
47 }
48 
~LogBufferElement()49 LogBufferElement::~LogBufferElement() {
50     delete [] mMsg;
51 }
52 
getTag() const53 uint32_t LogBufferElement::getTag() const {
54     if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {
55         return 0;
56     }
57     return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
58 }
59 
60 // caller must own and free character string
tidToName(pid_t tid)61 char *android::tidToName(pid_t tid) {
62     char *retval = NULL;
63     char buffer[256];
64     snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
65     int fd = open(buffer, O_RDONLY);
66     if (fd >= 0) {
67         ssize_t ret = read(fd, buffer, sizeof(buffer));
68         if (ret >= (ssize_t)sizeof(buffer)) {
69             ret = sizeof(buffer) - 1;
70         }
71         while ((ret > 0) && isspace(buffer[ret - 1])) {
72             --ret;
73         }
74         if (ret > 0) {
75             buffer[ret] = '\0';
76             retval = strdup(buffer);
77         }
78         close(fd);
79     }
80 
81     // if nothing for comm, check out cmdline
82     char *name = android::pidToName(tid);
83     if (!retval) {
84         retval = name;
85         name = NULL;
86     }
87 
88     // check if comm is truncated, see if cmdline has full representation
89     if (name) {
90         // impossible for retval to be NULL if name not NULL
91         size_t retval_len = strlen(retval);
92         size_t name_len = strlen(name);
93         // KISS: ToDo: Only checks prefix truncated, not suffix, or both
94         if ((retval_len < name_len) && !strcmp(retval, name + name_len - retval_len)) {
95             free(retval);
96             retval = name;
97         } else {
98             free(name);
99         }
100     }
101     return retval;
102 }
103 
104 // assumption: mMsg == NULL
populateDroppedMessage(char * & buffer,LogBuffer * parent)105 size_t LogBufferElement::populateDroppedMessage(char *&buffer,
106         LogBuffer *parent) {
107     static const char tag[] = "chatty";
108 
109     if (!__android_log_is_loggable(ANDROID_LOG_INFO, tag, ANDROID_LOG_VERBOSE)) {
110         return 0;
111     }
112 
113     static const char format_uid[] = "uid=%u%s%s expire %u line%s";
114     parent->lock();
115     char *name = parent->uidToName(mUid);
116     parent->unlock();
117     char *commName = android::tidToName(mTid);
118     if (!commName && (mTid != mPid)) {
119         commName = android::tidToName(mPid);
120     }
121     if (!commName) {
122         parent->lock();
123         commName = parent->pidToName(mPid);
124         parent->unlock();
125     }
126     size_t len = name ? strlen(name) : 0;
127     if (len && commName && !strncmp(name, commName, len)) {
128         if (commName[len] == '\0') {
129             free(commName);
130             commName = NULL;
131         } else {
132             free(name);
133             name = NULL;
134         }
135     }
136     if (name) {
137         char *p = NULL;
138         asprintf(&p, "(%s)", name);
139         if (p) {
140             free(name);
141             name = p;
142         }
143     }
144     if (commName) {
145         char *p = NULL;
146         asprintf(&p, " %s", commName);
147         if (p) {
148             free(commName);
149             commName = p;
150         }
151     }
152     // identical to below to calculate the buffer size required
153     len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
154                    commName ? commName : "",
155                    mDropped, (mDropped > 1) ? "s" : "");
156 
157     size_t hdrLen;
158     if (mLogId == LOG_ID_EVENTS) {
159         hdrLen = sizeof(android_log_event_string_t);
160     } else {
161         hdrLen = 1 + sizeof(tag);
162     }
163 
164     buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
165     if (!buffer) {
166         free(name);
167         free(commName);
168         return 0;
169     }
170 
171     size_t retval = hdrLen + len;
172     if (mLogId == LOG_ID_EVENTS) {
173         android_log_event_string_t *e = reinterpret_cast<android_log_event_string_t *>(buffer);
174 
175         e->header.tag = htole32(LOGD_LOG_TAG);
176         e->type = EVENT_TYPE_STRING;
177         e->length = htole32(len);
178     } else {
179         ++retval;
180         buffer[0] = ANDROID_LOG_INFO;
181         strcpy(buffer + 1, tag);
182     }
183 
184     snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
185              commName ? commName : "",
186              mDropped, (mDropped > 1) ? "s" : "");
187     free(name);
188     free(commName);
189 
190     return retval;
191 }
192 
flushTo(SocketClient * reader,LogBuffer * parent)193 uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {
194     struct logger_entry_v3 entry;
195 
196     memset(&entry, 0, sizeof(struct logger_entry_v3));
197 
198     entry.hdr_size = sizeof(struct logger_entry_v3);
199     entry.lid = mLogId;
200     entry.pid = mPid;
201     entry.tid = mTid;
202     entry.sec = mRealTime.tv_sec;
203     entry.nsec = mRealTime.tv_nsec;
204 
205     struct iovec iovec[2];
206     iovec[0].iov_base = &entry;
207     iovec[0].iov_len = sizeof(struct logger_entry_v3);
208 
209     char *buffer = NULL;
210 
211     if (!mMsg) {
212         entry.len = populateDroppedMessage(buffer, parent);
213         if (!entry.len) {
214             return mSequence;
215         }
216         iovec[1].iov_base = buffer;
217     } else {
218         entry.len = mMsgLen;
219         iovec[1].iov_base = mMsg;
220     }
221     iovec[1].iov_len = entry.len;
222 
223     uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence;
224 
225     if (buffer) {
226         free(buffer);
227     }
228 
229     return retval;
230 }
231