Home | History | Annotate | Download | only in logd
      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 
     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 
     49 LogBufferElement::~LogBufferElement() {
     50     delete [] mMsg;
     51 }
     52 
     53 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
     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
    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 
    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