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