logd: improve details on chatty records

(Cherry pick from commit 21fb7e0b75)

- Report applications UID, TID/PID by name.
- change wording to have an accurate connotation
- drop privilege check since filtered upstream

Bug: 19608965
Bug: 20334069
Bug: 20370119
Change-Id: I2b1c26580b4c2de293874214ff5ae745546f3cca
This commit is contained in:
Mark Salyzyn 2015-04-20 07:26:27 -07:00
parent 5a9d33ee1c
commit 95108f1844
6 changed files with 114 additions and 25 deletions

View File

@ -631,7 +631,7 @@ uint64_t LogBuffer::flushTo(
pthread_mutex_unlock(&mLogElementsLock);
// range locking in LastLogTimes looks after us
max = element->flushTo(reader);
max = element->flushTo(reader, this);
if (max == element->FLUSH_ERROR) {
return max;

View File

@ -74,6 +74,7 @@ public:
// helper
char *pidToName(pid_t pid) { return stats.pidToName(pid); }
uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
char *uidToName(uid_t uid) { return stats.uidToName(uid); }
private:
void maybePrune(log_id_t id);

View File

@ -14,7 +14,9 @@
* limitations under the License.
*/
#include <ctype.h>
#include <endian.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
@ -48,19 +50,89 @@ LogBufferElement::~LogBufferElement() {
delete [] mMsg;
}
// assumption: mMsg == NULL
size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged) {
static const char format_uid[] = "uid=%u dropped=%u";
static const size_t unprivileged_offset = 7;
static const char tag[] = "logd";
size_t len;
if (privileged) {
len = snprintf(NULL, 0, format_uid, mUid, mDropped);
} else {
len = snprintf(NULL, 0, format_uid + unprivileged_offset, mDropped);
// caller must own and free character string
static char *tidToName(pid_t tid) {
char *retval = NULL;
char buffer[256];
snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
int fd = open(buffer, O_RDONLY);
if (fd >= 0) {
ssize_t ret = read(fd, buffer, sizeof(buffer));
if (ret >= (ssize_t)sizeof(buffer)) {
ret = sizeof(buffer) - 1;
}
while ((ret > 0) && isspace(buffer[ret - 1])) {
--ret;
}
if (ret > 0) {
buffer[ret] = '\0';
retval = strdup(buffer);
}
close(fd);
}
// if nothing for comm, check out cmdline
char *name = android::pidToName(tid);
if (!retval) {
retval = name;
name = NULL;
}
// check if comm is truncated, see if cmdline has full representation
if (name) {
// impossible for retval to be NULL if name not NULL
size_t retval_len = strlen(retval);
size_t name_len = strlen(name);
// KISS: ToDo: Only checks prefix truncated, not suffix, or both
if ((retval_len < name_len) && !strcmp(retval, name + name_len - retval_len)) {
free(retval);
retval = name;
} else {
free(name);
}
}
return retval;
}
// assumption: mMsg == NULL
size_t LogBufferElement::populateDroppedMessage(char *&buffer,
LogBuffer *parent) {
static const char tag[] = "logd";
static const char format_uid[] = "uid=%u%s too chatty%s, expire %u line%s";
char *name = parent->uidToName(mUid);
char *commName = tidToName(mTid);
if (!commName && (mTid != mPid)) {
commName = tidToName(mPid);
}
if (!commName) {
commName = parent->pidToName(mPid);
}
if (name && commName && !strcmp(name, commName)) {
free(commName);
commName = NULL;
}
if (name) {
char *p = NULL;
asprintf(&p, "(%s)", name);
if (p) {
free(name);
name = p;
}
}
if (commName) {
char *p = NULL;
asprintf(&p, " comm=%s", commName);
if (p) {
free(commName);
commName = p;
}
}
// identical to below to calculate the buffer size required
size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
commName ? commName : "",
mDropped, (mDropped > 1) ? "s" : "");
size_t hdrLen;
if (mLogId == LOG_ID_EVENTS) {
hdrLen = sizeof(android_log_event_string_t);
@ -70,6 +142,8 @@ size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged)
buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
if (!buffer) {
free(name);
free(commName);
return 0;
}
@ -86,16 +160,16 @@ size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged)
strcpy(buffer + 1, tag);
}
if (privileged) {
snprintf(buffer + hdrLen, len + 1, format_uid, mUid, mDropped);
} else {
snprintf(buffer + hdrLen, len + 1, format_uid + unprivileged_offset, mDropped);
}
snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
commName ? commName : "",
mDropped, (mDropped > 1) ? "s" : "");
free(name);
free(commName);
return retval;
}
uint64_t LogBufferElement::flushTo(SocketClient *reader) {
uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {
struct logger_entry_v3 entry;
memset(&entry, 0, sizeof(struct logger_entry_v3));
@ -114,7 +188,7 @@ uint64_t LogBufferElement::flushTo(SocketClient *reader) {
char *buffer = NULL;
if (!mMsg) {
entry.len = populateDroppedMessage(buffer, clientHasLogCredentials(reader));
entry.len = populateDroppedMessage(buffer, parent);
if (!entry.len) {
return mSequence;
}

View File

@ -28,15 +28,19 @@
namespace android {
// Furnished in main.cpp. Caller must own and free returned value
// This function is designed for a single caller and is NOT thread-safe
char *uidToName(uid_t uid);
// Furnished in LogStatistics.cpp. Caller must own and free returned value
char *pidToName(pid_t pid);
}
static inline bool worstUidEnabledForLogid(log_id_t id) {
return (id != LOG_ID_CRASH) && (id != LOG_ID_EVENTS);
}
class LogBuffer;
class LogBufferElement {
const log_id_t mLogId;
const uid_t mUid;
@ -52,7 +56,8 @@ class LogBufferElement {
static atomic_int_fast64_t sequence;
// assumption: mMsg == NULL
size_t populateDroppedMessage(char *&buffer, bool privileged);
size_t populateDroppedMessage(char *&buffer,
LogBuffer *parent);
public:
LogBufferElement(log_id_t log_id, log_time realtime,
@ -78,7 +83,7 @@ public:
log_time getRealTime(void) const { return mRealTime; }
static const uint64_t FLUSH_ERROR;
uint64_t flushTo(SocketClient *writer);
uint64_t flushTo(SocketClient *writer, LogBuffer *parent);
};
#endif

View File

@ -39,7 +39,7 @@ LogStatistics::LogStatistics()
namespace android {
// caller must own and free character string
static char *pidToName(pid_t pid) {
char *pidToName(pid_t pid) {
char *retval = NULL;
if (pid == 0) { // special case from auditd for kernel
retval = strdup("logd.auditd");

View File

@ -210,18 +210,26 @@ static void *reinit_thread_start(void * /*obj*/) {
return NULL;
}
static sem_t sem_name;
char *android::uidToName(uid_t u) {
if (!u || !reinit_running) {
return NULL;
}
// Not multi-thread safe, we know there is only one caller
sem_wait(&sem_name);
// Not multi-thread safe, we use sem_name to protect
uid = u;
name = NULL;
sem_post(&reinit);
sem_wait(&uidName);
return name;
char *ret = name;
sem_post(&sem_name);
return ret;
}
// Serves as a global method to trigger reinitialization
@ -277,6 +285,7 @@ int main(int argc, char *argv[]) {
// Reinit Thread
sem_init(&reinit, 0, 0);
sem_init(&uidName, 0, 0);
sem_init(&sem_name, 0, 1);
pthread_attr_t attr;
if (!pthread_attr_init(&attr)) {
struct sched_param param;