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