diff options
author | Mark Salyzyn <salyzyn@google.com> | 2016-03-10 09:50:08 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@google.com> | 2016-03-22 13:03:36 -0700 |
commit | d4b061bde280fce9b5426b5738a02d42ec263c48 (patch) | |
tree | 4be93d57461360452f7d7af3490f1119da581dc3 /liblog | |
parent | 018a96d03f0d452bf078084eedcd5693da42308d (diff) | |
download | core-d4b061bde280fce9b5426b5738a02d42ec263c48.tar.gz core-d4b061bde280fce9b5426b5738a02d42ec263c48.tar.bz2 core-d4b061bde280fce9b5426b5738a02d42ec263c48.zip |
liblog: add __android_log_pmsg_file_write
- This is considered an Android Private function, not exported
for general use.
- goal is to record a file's content into a series of log
messages into pmsg, to be retrieved after a reboot for
transfer to a persistent location.
- filename reference is converted to a tag-unique
"<dirbase>:<filebase>".
- buffer and length representing the filename contents are
recorded, along with a sequence number placed into the nsec
time field to ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE.
- Add a gTest for this function.
Bug: 27176738
Change-Id: If93df3ae8bfc1bb75516d4a1fd8dae0301af644b
Diffstat (limited to 'liblog')
-rw-r--r-- | liblog/pmsg_writer.c | 111 | ||||
-rw-r--r-- | liblog/tests/liblog_test.cpp | 15 |
2 files changed, 125 insertions, 1 deletions
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c index 7a89e5d54..7034cebaa 100644 --- a/liblog/pmsg_writer.c +++ b/liblog/pmsg_writer.c @@ -157,3 +157,114 @@ static int pmsgWrite(log_id_t logId, struct timespec *ts, return ret; } + +/* + * Virtual pmsg filesystem + * + * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a + * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the + * file. + * + * Will hijack the header.realtime.tv_nsec field for a sequence number in usec. + */ + +static inline const char *strnrchr(const char *buf, size_t len, char c) { + const char *cp = buf + len; + while ((--cp > buf) && (*cp != c)); + if (cp <= buf) { + return buf + len; + } + return cp; +} + +/* Write a buffer as filename references (tag = <basedir>:<basename>) */ +LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_write( + log_id_t logId, + char prio, + const char *filename, + const char *buf, size_t len) { + int fd; + size_t length, packet_len; + const char *tag; + char *cp, *slash; + struct timespec ts; + struct iovec vec[3]; + + /* Make sure the logId value is not a bad idea */ + if ((logId == LOG_ID_KERNEL) || /* Verbotten */ + (logId == LOG_ID_EVENTS) || /* Do not support binary content */ + (logId == LOG_ID_SECURITY) || /* Bad idea to allow */ + ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */ + return -EINVAL; + } + + clock_gettime(android_log_clockid(), &ts); + + cp = strdup(filename); + if (!cp) { + return -ENOMEM; + } + + fd = pmsgLoggerWrite.context.fd; + if (fd < 0) { + __android_log_lock(); + fd = pmsgOpen(); + __android_log_unlock(); + if (fd < 0) { + return -EBADF; + } + } + + tag = cp; + slash = strrchr(cp, '/'); + if (slash) { + *slash = ':'; + slash = strrchr(cp, '/'); + if (slash) { + tag = slash + 1; + } + } + + length = strlen(tag) + 1; + packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length; + + vec[0].iov_base = &prio; + vec[0].iov_len = sizeof(char); + vec[1].iov_base = (unsigned char *)tag; + vec[1].iov_len = length; + + for (ts.tv_nsec = 0, length = len; + length; + ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) { + ssize_t ret; + size_t transfer; + + if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= + ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) { + len -= length; + break; + } + + transfer = length; + if (transfer > packet_len) { + transfer = strnrchr(buf, packet_len - 1, '\n') - buf; + if ((transfer < length) && (buf[transfer] == '\n')) { + ++transfer; + } + } + + vec[2].iov_base = (unsigned char *)buf; + vec[2].iov_len = transfer; + + ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0])); + + if (ret <= 0) { + free(cp); + return ret; + } + length -= transfer; + buf += transfer; + } + free(cp); + return len; +} diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp index 2767f73b0..f3157913e 100644 --- a/liblog/tests/liblog_test.cpp +++ b/liblog/tests/liblog_test.cpp @@ -957,7 +957,10 @@ Good Signior Leonato, you are come to meet your\n\ trouble: the fashion of the world is to avoid\n\ cost, and you encounter it\n\ LEONATO\n\ -Never came trouble to my house in the likeness of your grace"; +Never came trouble to my house in the likeness of your grace,\n\ +for trouble being gone, comfort should remain, but\n\ +when you depart from me, sorrow abides and happiness\n\ +takes his leave."; TEST(liblog, max_payload) { pid_t pid = getpid(); @@ -2520,3 +2523,13 @@ TEST(liblog, create_android_logger_overflow) { EXPECT_LE(0, android_log_destroy(&ctx)); ASSERT_TRUE(NULL == ctx); } + +static const char __pmsg_file[] = + "/data/william-shakespeare/MuchAdoAboutNothing.txt"; + +TEST(liblog, __android_log_pmsg_file_write) { + EXPECT_LT(0, __android_log_pmsg_file_write( + LOG_ID_CRASH, ANDROID_LOG_VERBOSE, + __pmsg_file, max_payload_buf, sizeof(max_payload_buf))); + fprintf(stderr, "Reboot, ensure file %s matches\n", __pmsg_file); +} |