liblog: add __android_log_pmsg_file_write

(cherry pick from commit d4b061bde2)

- 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
This commit is contained in:
Mark Salyzyn 2016-03-10 09:50:08 -08:00
parent facf94c74a
commit 10bdf61e5f
3 changed files with 145 additions and 1 deletions

View File

@ -19,7 +19,10 @@
#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
/* Android private interfaces */
#include <stdint.h>
#include <sys/types.h>
#include <log/log.h>
#include <log/log_read.h>
@ -95,4 +98,21 @@ typedef struct __attribute__((__packed__)) {
char data[];
} android_log_event_string_t;
#if defined(__cplusplus)
extern "C" {
#endif
#define ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE 256 /* 1MB file */
#define ANDROID_LOG_PMSG_FILE_SEQUENCE 1000
ssize_t __android_log_pmsg_file_write(
log_id_t logId,
char prio,
const char *filename,
const char *buf, size_t len);
#if defined(__cplusplus)
}
#endif
#endif /* _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_ */

View File

@ -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;
}

View File

@ -896,7 +896,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();
@ -2451,3 +2454,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);
}