logd: annotate worst-UID pruned entries
- internal dropped entries are associated by prune by worst UID
and are applied by UID and by PID
- track dropped entries by rewriting them in place
- merge similar dropped entries together for same UID(implied),
PID and TID so that blame can more clearly be placed
- allow aging of dropped entries by the general backgound pruning
- report individual dropped entries formatted to reader
- add statistics to track dropped entries by UID, the combination
of statistics and dropped logging can track over-the-top Chattiest
clients.
Bug: 19608965
Change-Id: Ibc68480df0c69c55703270cd70c6b26aea165853
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 5e780b5..a173e63 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -14,14 +14,17 @@
* limitations under the License.
*/
+#include <endian.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <log/logger.h>
+#include <private/android_logger.h>
#include "LogBufferElement.h"
+#include "LogCommand.h"
#include "LogReader.h"
const uint64_t LogBufferElement::FLUSH_ERROR(0);
@@ -45,11 +48,59 @@
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);
+ }
+
+ size_t hdrLen;
+ if (mLogId == LOG_ID_EVENTS) {
+ hdrLen = sizeof(android_log_event_string_t);
+ } else {
+ hdrLen = 1 + sizeof(tag);
+ }
+
+ buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
+ if (!buffer) {
+ return 0;
+ }
+
+ size_t retval = hdrLen + len;
+ if (mLogId == LOG_ID_EVENTS) {
+ android_log_event_string_t *e = reinterpret_cast<android_log_event_string_t *>(buffer);
+
+ e->header.tag = htole32(LOGD_LOG_TAG);
+ e->type = EVENT_TYPE_STRING;
+ e->length = htole32(len);
+ } else {
+ ++retval;
+ buffer[0] = ANDROID_LOG_INFO;
+ 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);
+ }
+
+ return retval;
+}
+
uint64_t LogBufferElement::flushTo(SocketClient *reader) {
struct logger_entry_v3 entry;
+
memset(&entry, 0, sizeof(struct logger_entry_v3));
+
entry.hdr_size = sizeof(struct logger_entry_v3);
- entry.len = mMsgLen;
entry.lid = mLogId;
entry.pid = mPid;
entry.tid = mTid;
@@ -59,11 +110,26 @@
struct iovec iovec[2];
iovec[0].iov_base = &entry;
iovec[0].iov_len = sizeof(struct logger_entry_v3);
- iovec[1].iov_base = mMsg;
- iovec[1].iov_len = mMsgLen;
- if (reader->sendDatav(iovec, 2)) {
- return FLUSH_ERROR;
+
+ char *buffer = NULL;
+
+ if (!mMsg) {
+ entry.len = populateDroppedMessage(buffer, clientHasLogCredentials(reader));
+ if (!entry.len) {
+ return mSequence;
+ }
+ iovec[1].iov_base = buffer;
+ } else {
+ entry.len = mMsgLen;
+ iovec[1].iov_base = mMsg;
+ }
+ iovec[1].iov_len = entry.len;
+
+ uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence;
+
+ if (buffer) {
+ free(buffer);
}
- return mSequence;
+ return retval;
}