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