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
32const uint64_t LogBufferElement::FLUSH_ERROR(0);
33atomic_int_fast64_t LogBufferElement::sequence(1);
34
35LogBufferElement::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
49LogBufferElement::~LogBufferElement() {
50    delete [] mMsg;
51}
52
53uint32_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
61char *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
105size_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
193uint64_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