Merge "liblog: simplify logd 'command' functions and struct logger"
This commit is contained in:
commit
7d16aedc47
10 changed files with 134 additions and 361 deletions
|
|
@ -494,7 +494,7 @@ void android_closeEventTagMap(EventTagMap* map) {
|
||||||
|
|
||||||
// Cache miss, go to logd to acquire a public reference.
|
// Cache miss, go to logd to acquire a public reference.
|
||||||
// Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
|
// Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
|
||||||
static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
|
static const TagFmt* __getEventTag([[maybe_unused]] EventTagMap* map, unsigned int tag) {
|
||||||
// call event tag service to arrange for a new tag
|
// call event tag service to arrange for a new tag
|
||||||
char* buf = NULL;
|
char* buf = NULL;
|
||||||
// Can not use android::base::StringPrintf, asprintf + free instead.
|
// Can not use android::base::StringPrintf, asprintf + free instead.
|
||||||
|
|
@ -515,8 +515,9 @@ static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
|
||||||
} else {
|
} else {
|
||||||
size = ret;
|
size = ret;
|
||||||
}
|
}
|
||||||
|
#ifdef __ANDROID__
|
||||||
// Ask event log tag service for an existing entry
|
// Ask event log tag service for an existing entry
|
||||||
if (__send_log_msg(buf, size) >= 0) {
|
if (SendLogdControlMessage(buf, size) >= 0) {
|
||||||
buf[size - 1] = '\0';
|
buf[size - 1] = '\0';
|
||||||
char* ep;
|
char* ep;
|
||||||
unsigned long val = strtoul(buf, &ep, 10); // return size
|
unsigned long val = strtoul(buf, &ep, 10); // return size
|
||||||
|
|
@ -529,6 +530,7 @@ static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -618,8 +620,9 @@ int android_lookupEventTagNum(EventTagMap* map, const char* tagname, const char*
|
||||||
} else {
|
} else {
|
||||||
size = ret;
|
size = ret;
|
||||||
}
|
}
|
||||||
|
#ifdef __ANDROID__
|
||||||
// Ask event log tag service for an allocation
|
// Ask event log tag service for an allocation
|
||||||
if (__send_log_msg(buf, size) >= 0) {
|
if (SendLogdControlMessage(buf, size) >= 0) {
|
||||||
buf[size - 1] = '\0';
|
buf[size - 1] = '\0';
|
||||||
unsigned long val = strtoul(buf, &cp, 10); // return size
|
unsigned long val = strtoul(buf, &cp, 10); // return size
|
||||||
if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
|
if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
|
||||||
|
|
@ -635,6 +638,7 @@ int android_lookupEventTagNum(EventTagMap* map, const char* tagname, const char*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -650,10 +650,6 @@ int fakeLogOpen(const char* pathName) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t __send_log_msg(char*, size_t) {
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
int __android_log_is_loggable(int prio, const char*, int def) {
|
int __android_log_is_loggable(int prio, const char*, int def) {
|
||||||
int logLevel = def;
|
int logLevel = def;
|
||||||
return logLevel >= 0 && prio >= logLevel;
|
return logLevel >= 0 && prio >= logLevel;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ int fakeLogOpen(const char* pathName);
|
||||||
int fakeLogClose(int fd);
|
int fakeLogClose(int fd);
|
||||||
ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count);
|
ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count);
|
||||||
|
|
||||||
ssize_t __send_log_msg(char*, size_t);
|
|
||||||
int __android_log_is_loggable(int prio, const char*, int def);
|
int __android_log_is_loggable(int prio, const char*, int def);
|
||||||
int __android_log_is_loggable_len(int prio, const char*, size_t, int def);
|
int __android_log_is_loggable_len(int prio, const char*, size_t, int def);
|
||||||
int __android_log_is_debuggable();
|
int __android_log_is_debuggable();
|
||||||
|
|
|
||||||
|
|
@ -40,39 +40,16 @@
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
static int LogdAvailable(log_id_t LogId);
|
static int LogdAvailable(log_id_t LogId);
|
||||||
static int LogdVersion(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
static int LogdRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
static int LogdRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
||||||
struct log_msg* log_msg);
|
struct log_msg* log_msg);
|
||||||
static int LogdPoll(struct logger_list* logger_list, struct android_log_transport_context* transp);
|
|
||||||
static void LogdClose(struct logger_list* logger_list,
|
static void LogdClose(struct logger_list* logger_list,
|
||||||
struct android_log_transport_context* transp);
|
struct android_log_transport_context* transp);
|
||||||
static int LogdClear(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
static ssize_t LogdSetSize(struct logger* logger, struct android_log_transport_context* transp,
|
|
||||||
size_t size);
|
|
||||||
static ssize_t LogdGetSize(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
static ssize_t LogdGetReadableSize(struct logger* logger,
|
|
||||||
struct android_log_transport_context* transp);
|
|
||||||
static ssize_t LogdGetPrune(struct logger_list* logger,
|
|
||||||
struct android_log_transport_context* transp, char* buf, size_t len);
|
|
||||||
static ssize_t LogdSetPrune(struct logger_list* logger,
|
|
||||||
struct android_log_transport_context* transp, char* buf, size_t len);
|
|
||||||
static ssize_t LogdGetStats(struct logger_list* logger,
|
|
||||||
struct android_log_transport_context* transp, char* buf, size_t len);
|
|
||||||
|
|
||||||
struct android_log_transport_read logdLoggerRead = {
|
struct android_log_transport_read logdLoggerRead = {
|
||||||
.name = "logd",
|
.name = "logd",
|
||||||
.available = LogdAvailable,
|
.available = LogdAvailable,
|
||||||
.version = LogdVersion,
|
|
||||||
.close = LogdClose,
|
.close = LogdClose,
|
||||||
.read = LogdRead,
|
.read = LogdRead,
|
||||||
.poll = LogdPoll,
|
|
||||||
.clear = LogdClear,
|
|
||||||
.setSize = LogdSetSize,
|
|
||||||
.getSize = LogdGetSize,
|
|
||||||
.getReadableSize = LogdGetReadableSize,
|
|
||||||
.getPrune = LogdGetPrune,
|
|
||||||
.setPrune = LogdSetPrune,
|
|
||||||
.getStats = LogdGetStats,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int LogdAvailable(log_id_t logId) {
|
static int LogdAvailable(log_id_t logId) {
|
||||||
|
|
@ -116,7 +93,7 @@ static int socket_local_client(const std::string& name, int type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* worker for sending the command to the logger */
|
/* worker for sending the command to the logger */
|
||||||
static ssize_t send_log_msg(struct logger* logger, const char* msg, char* buf, size_t buf_size) {
|
ssize_t SendLogdControlMessage(char* buf, size_t buf_size) {
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
size_t len;
|
size_t len;
|
||||||
char* cp;
|
char* cp;
|
||||||
|
|
@ -126,10 +103,6 @@ static ssize_t send_log_msg(struct logger* logger, const char* msg, char* buf, s
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg) {
|
|
||||||
snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned)-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
len = strlen(buf) + 1;
|
len = strlen(buf) + 1;
|
||||||
ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
|
ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
|
|
@ -180,10 +153,6 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t __send_log_msg(char* buf, size_t buf_size) {
|
|
||||||
return send_log_msg(NULL, NULL, buf, buf_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int check_log_success(char* buf, ssize_t ret) {
|
static int check_log_success(char* buf, ssize_t ret) {
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -197,17 +166,28 @@ static int check_log_success(char* buf, ssize_t ret) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LogdClear(struct logger* logger, struct android_log_transport_context*) {
|
int android_logger_clear(struct logger* logger) {
|
||||||
|
if (!android_logger_is_logd(logger)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
uint32_t log_id = android_logger_get_id(logger);
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
snprintf(buf, sizeof(buf), "clear %" PRIu32, log_id);
|
||||||
|
|
||||||
return check_log_success(buf, send_log_msg(logger, "clear %d", buf, sizeof(buf)));
|
return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns the total size of the log's ring buffer */
|
/* returns the total size of the log's ring buffer */
|
||||||
static ssize_t LogdGetSize(struct logger* logger, struct android_log_transport_context*) {
|
long android_logger_get_log_size(struct logger* logger) {
|
||||||
char buf[512];
|
if (!android_logger_is_logd(logger)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
|
uint32_t log_id = android_logger_get_id(logger);
|
||||||
|
char buf[512];
|
||||||
|
snprintf(buf, sizeof(buf), "getLogSize %" PRIu32, log_id);
|
||||||
|
|
||||||
|
ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -219,23 +199,32 @@ static ssize_t LogdGetSize(struct logger* logger, struct android_log_transport_c
|
||||||
return atol(buf);
|
return atol(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t LogdSetSize(struct logger* logger, struct android_log_transport_context*,
|
int android_logger_set_log_size(struct logger* logger, unsigned long size) {
|
||||||
size_t size) {
|
if (!android_logger_is_logd(logger)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t log_id = android_logger_get_id(logger);
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
snprintf(buf, sizeof(buf), "setLogSize %" PRIu32 " %lu", log_id, size);
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size);
|
return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
|
||||||
|
|
||||||
return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns the readable size of the log's ring buffer (that is, amount of the
|
* returns the readable size of the log's ring buffer (that is, amount of the
|
||||||
* log consumed)
|
* log consumed)
|
||||||
*/
|
*/
|
||||||
static ssize_t LogdGetReadableSize(struct logger* logger, struct android_log_transport_context*) {
|
long android_logger_get_log_readable_size(struct logger* logger) {
|
||||||
char buf[512];
|
if (!android_logger_is_logd(logger)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
|
uint32_t log_id = android_logger_get_id(logger);
|
||||||
|
char buf[512];
|
||||||
|
snprintf(buf, sizeof(buf), "getLogSizeUsed %" PRIu32, log_id);
|
||||||
|
|
||||||
|
ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -247,20 +236,15 @@ static ssize_t LogdGetReadableSize(struct logger* logger, struct android_log_tra
|
||||||
return atol(buf);
|
return atol(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int android_logger_get_log_version(struct logger*) {
|
||||||
* returns the logger version
|
return 4;
|
||||||
*/
|
|
||||||
static int LogdVersion(struct logger*, struct android_log_transport_context*) {
|
|
||||||
uid_t uid = __android_log_uid();
|
|
||||||
return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ssize_t android_logger_get_statistics(struct logger_list* logger_list, char* buf, size_t len) {
|
||||||
* returns statistics
|
if (logger_list->mode & ANDROID_LOG_PSTORE) {
|
||||||
*/
|
return -EINVAL;
|
||||||
static ssize_t LogdGetStats(struct logger_list* logger_list, struct android_log_transport_context*,
|
}
|
||||||
char* buf, size_t len) {
|
|
||||||
struct logger* logger;
|
|
||||||
char* cp = buf;
|
char* cp = buf;
|
||||||
size_t remaining = len;
|
size_t remaining = len;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
@ -270,27 +254,35 @@ static ssize_t LogdGetStats(struct logger_list* logger_list, struct android_log_
|
||||||
remaining -= n;
|
remaining -= n;
|
||||||
cp += n;
|
cp += n;
|
||||||
|
|
||||||
logger_for_each(logger, logger_list) {
|
for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
|
||||||
n = snprintf(cp, remaining, " %d", logger->logId);
|
if ((1 << log_id) & logger_list->log_mask) {
|
||||||
n = MIN(n, remaining);
|
n = snprintf(cp, remaining, " %zu", log_id);
|
||||||
remaining -= n;
|
n = MIN(n, remaining);
|
||||||
cp += n;
|
remaining -= n;
|
||||||
|
cp += n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger_list->pid) {
|
if (logger_list->pid) {
|
||||||
snprintf(cp, remaining, " pid=%u", logger_list->pid);
|
snprintf(cp, remaining, " pid=%u", logger_list->pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return send_log_msg(NULL, NULL, buf, len);
|
return SendLogdControlMessage(buf, len);
|
||||||
|
}
|
||||||
|
ssize_t android_logger_get_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
|
||||||
|
if (logger_list->mode & ANDROID_LOG_PSTORE) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, len, "getPruneList");
|
||||||
|
return SendLogdControlMessage(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t LogdGetPrune(struct logger_list*, struct android_log_transport_context*, char* buf,
|
int android_logger_set_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
|
||||||
size_t len) {
|
if (logger_list->mode & ANDROID_LOG_PSTORE) {
|
||||||
return send_log_msg(NULL, "getPruneList", buf, len);
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t LogdSetPrune(struct logger_list*, struct android_log_transport_context*, char* buf,
|
|
||||||
size_t len) {
|
|
||||||
const char cmd[] = "setPruneList ";
|
const char cmd[] = "setPruneList ";
|
||||||
const size_t cmdlen = sizeof(cmd) - 1;
|
const size_t cmdlen = sizeof(cmd) - 1;
|
||||||
|
|
||||||
|
|
@ -301,11 +293,10 @@ static ssize_t LogdSetPrune(struct logger_list*, struct android_log_transport_co
|
||||||
buf[len - 1] = '\0';
|
buf[len - 1] = '\0';
|
||||||
memcpy(buf, cmd, cmdlen);
|
memcpy(buf, cmd, cmdlen);
|
||||||
|
|
||||||
return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
|
return check_log_success(buf, SendLogdControlMessage(buf, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int logdOpen(struct logger_list* logger_list, struct android_log_transport_context* transp) {
|
static int logdOpen(struct logger_list* logger_list, struct android_log_transport_context* transp) {
|
||||||
struct logger* logger;
|
|
||||||
char buffer[256], *cp, c;
|
char buffer[256], *cp, c;
|
||||||
int ret, remaining, sock;
|
int ret, remaining, sock;
|
||||||
|
|
||||||
|
|
@ -333,12 +324,15 @@ static int logdOpen(struct logger_list* logger_list, struct android_log_transpor
|
||||||
cp += 5;
|
cp += 5;
|
||||||
c = '=';
|
c = '=';
|
||||||
remaining = sizeof(buffer) - (cp - buffer);
|
remaining = sizeof(buffer) - (cp - buffer);
|
||||||
logger_for_each(logger, logger_list) {
|
|
||||||
ret = snprintf(cp, remaining, "%c%u", c, logger->logId);
|
for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
|
||||||
ret = MIN(ret, remaining);
|
if ((1 << log_id) & logger_list->log_mask) {
|
||||||
remaining -= ret;
|
ret = snprintf(cp, remaining, "%c%zu", c, log_id);
|
||||||
cp += ret;
|
ret = MIN(ret, remaining);
|
||||||
c = ',';
|
remaining -= ret;
|
||||||
|
cp += ret;
|
||||||
|
c = ',';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger_list->tail) {
|
if (logger_list->tail) {
|
||||||
|
|
@ -412,27 +406,6 @@ static int LogdRead(struct logger_list* logger_list, struct android_log_transpor
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LogdPoll(struct logger_list* logger_list, struct android_log_transport_context* transp) {
|
|
||||||
struct pollfd p;
|
|
||||||
|
|
||||||
int ret = logdOpen(logger_list, transp);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&p, 0, sizeof(p));
|
|
||||||
p.fd = ret;
|
|
||||||
p.events = POLLIN;
|
|
||||||
ret = poll(&p, 1, 20);
|
|
||||||
if ((ret > 0) && !(p.revents & POLLIN)) {
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
if ((ret == -1) && errno) {
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close all the logs */
|
/* Close all the logs */
|
||||||
static void LogdClose(struct logger_list*, struct android_log_transport_context* transp) {
|
static void LogdClose(struct logger_list*, struct android_log_transport_context* transp) {
|
||||||
int sock = atomic_exchange(&transp->context.sock, -1);
|
int sock = atomic_exchange(&transp->context.sock, -1);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,6 @@
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
ssize_t __send_log_msg(char* buf, size_t buf_size);
|
ssize_t SendLogdControlMessage(char* buf, size_t buf_size);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ struct android_log_transport_read {
|
||||||
|
|
||||||
/* Does not cause resources to be taken */
|
/* Does not cause resources to be taken */
|
||||||
int (*available)(log_id_t logId);
|
int (*available)(log_id_t logId);
|
||||||
int (*version)(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
/* Release resources taken by the following interfaces */
|
/* Release resources taken by the following interfaces */
|
||||||
void (*close)(struct logger_list* logger_list, struct android_log_transport_context* transp);
|
void (*close)(struct logger_list* logger_list, struct android_log_transport_context* transp);
|
||||||
/*
|
/*
|
||||||
|
|
@ -62,53 +61,37 @@ struct android_log_transport_read {
|
||||||
*/
|
*/
|
||||||
int (*read)(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
int (*read)(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
||||||
struct log_msg* log_msg);
|
struct log_msg* log_msg);
|
||||||
/* Must only be called if not ANDROID_LOG_NONBLOCK (blocking) */
|
|
||||||
int (*poll)(struct logger_list* logger_list, struct android_log_transport_context* transp);
|
|
||||||
|
|
||||||
int (*clear)(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
ssize_t (*setSize)(struct logger* logger, struct android_log_transport_context* transp,
|
|
||||||
size_t size);
|
|
||||||
ssize_t (*getSize)(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
ssize_t (*getReadableSize)(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
|
|
||||||
ssize_t (*getPrune)(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
|
||||||
char* buf, size_t len);
|
|
||||||
ssize_t (*setPrune)(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
|
||||||
char* buf, size_t len);
|
|
||||||
ssize_t (*getStats)(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
|
||||||
char* buf, size_t len);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct android_log_transport_context {
|
struct android_log_transport_context {
|
||||||
union android_log_context_union context; /* zero init per-transport context */
|
union android_log_context_union context; /* zero init per-transport context */
|
||||||
|
|
||||||
struct android_log_transport_read* transport;
|
struct android_log_transport_read* transport;
|
||||||
unsigned logMask; /* mask of requested log buffers */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct logger_list {
|
struct logger_list {
|
||||||
struct listnode logger;
|
|
||||||
android_log_transport_context transport_context;
|
android_log_transport_context transport_context;
|
||||||
bool transport_initialized;
|
bool transport_initialized;
|
||||||
int mode;
|
int mode;
|
||||||
unsigned int tail;
|
unsigned int tail;
|
||||||
log_time start;
|
log_time start;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
uint32_t log_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct logger {
|
// Format for a 'logger' entry: uintptr_t where only the bottom 32 bits are used.
|
||||||
struct listnode node;
|
// bit 31: Set if this 'logger' is for logd.
|
||||||
struct logger_list* parent;
|
// bit 30: Set if this 'logger' is for pmsg
|
||||||
|
// bits 0-2: the decimal value of the log buffer.
|
||||||
|
// Other bits are unused.
|
||||||
|
|
||||||
log_id_t logId;
|
#define LOGGER_LOGD (1 << 31)
|
||||||
};
|
#define LOGGER_PMSG (1 << 30)
|
||||||
|
#define LOGGER_LOG_ID_MASK ((1 << 3) - 1)
|
||||||
|
|
||||||
/* assumes caller has structures read-locked, single threaded, or fenced */
|
inline bool android_logger_is_logd(struct logger* logger) {
|
||||||
#define logger_for_each(logp, logger_list) \
|
return reinterpret_cast<uintptr_t>(logger) & LOGGER_LOGD;
|
||||||
for ((logp) = node_to_item((logger_list)->logger.next, struct logger, node); \
|
}
|
||||||
((logp) != node_to_item(&(logger_list)->logger, struct logger, node)) && \
|
|
||||||
((logp)->parent == (logger_list)); \
|
|
||||||
(logp) = node_to_item((logp)->node.next, struct logger, node))
|
|
||||||
|
|
||||||
/* OS specific dribs and drabs */
|
/* OS specific dribs and drabs */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -32,211 +33,53 @@
|
||||||
#include "log_portability.h"
|
#include "log_portability.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
/* android_logger_alloc unimplemented, no use case */
|
|
||||||
/* android_logger_free not exported */
|
|
||||||
static void android_logger_free(struct logger* logger) {
|
|
||||||
if (!logger) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_remove(&logger->node);
|
|
||||||
|
|
||||||
free(logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* android_logger_alloc unimplemented, no use case */
|
|
||||||
|
|
||||||
/* method for getting the associated sublog id */
|
/* method for getting the associated sublog id */
|
||||||
log_id_t android_logger_get_id(struct logger* logger) {
|
log_id_t android_logger_get_id(struct logger* logger) {
|
||||||
return ((struct logger*)logger)->logId;
|
return static_cast<log_id_t>(reinterpret_cast<uintptr_t>(logger) & LOGGER_LOG_ID_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_transport_context(struct logger_list* logger_list) {
|
static struct logger_list* android_logger_list_alloc_internal(int mode, unsigned int tail,
|
||||||
|
log_time start, pid_t pid) {
|
||||||
|
auto* logger_list = static_cast<struct logger_list*>(calloc(1, sizeof(struct logger_list)));
|
||||||
if (!logger_list) {
|
if (!logger_list) {
|
||||||
return -EINVAL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list_empty(&logger_list->logger)) {
|
logger_list->mode = mode;
|
||||||
return -EINVAL;
|
logger_list->start = start;
|
||||||
}
|
logger_list->tail = tail;
|
||||||
|
logger_list->pid = pid;
|
||||||
if (logger_list->transport_initialized) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (FAKE_LOG_DEVICE == 0)
|
#if (FAKE_LOG_DEVICE == 0)
|
||||||
extern struct android_log_transport_read logdLoggerRead;
|
extern struct android_log_transport_read logdLoggerRead;
|
||||||
extern struct android_log_transport_read pmsgLoggerRead;
|
extern struct android_log_transport_read pmsgLoggerRead;
|
||||||
|
|
||||||
struct android_log_transport_read* transport;
|
logger_list->transport_context.transport =
|
||||||
transport = (logger_list->mode & ANDROID_LOG_PSTORE) ? &pmsgLoggerRead : &logdLoggerRead;
|
(mode & ANDROID_LOG_PSTORE) ? &pmsgLoggerRead : &logdLoggerRead;
|
||||||
|
|
||||||
struct logger* logger;
|
|
||||||
unsigned logMask = 0;
|
|
||||||
|
|
||||||
logger_for_each(logger, logger_list) {
|
|
||||||
log_id_t logId = logger->logId;
|
|
||||||
|
|
||||||
if (logId == LOG_ID_SECURITY && __android_log_uid() != AID_SYSTEM) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (transport->read && (!transport->available || transport->available(logId) >= 0)) {
|
|
||||||
logMask |= 1 << logId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!logMask) {
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger_list->transport_context.transport = transport;
|
|
||||||
logger_list->transport_context.logMask = logMask;
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define LOGGER_FUNCTION(logger, def, func, args...) \
|
return logger_list;
|
||||||
ssize_t ret = -EINVAL; \
|
|
||||||
\
|
|
||||||
if (!logger) { \
|
|
||||||
return ret; \
|
|
||||||
} \
|
|
||||||
ret = init_transport_context(logger->parent); \
|
|
||||||
if (ret < 0) { \
|
|
||||||
return ret; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
ret = (def); \
|
|
||||||
android_log_transport_context* transport_context = &logger->parent->transport_context; \
|
|
||||||
if (transport_context->logMask & (1 << logger->logId) && transport_context->transport && \
|
|
||||||
transport_context->transport->func) { \
|
|
||||||
ssize_t retval = (transport_context->transport->func)(logger, transport_context, ##args); \
|
|
||||||
if (ret >= 0 || ret == (def)) { \
|
|
||||||
ret = retval; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return ret
|
|
||||||
|
|
||||||
int android_logger_clear(struct logger* logger) {
|
|
||||||
LOGGER_FUNCTION(logger, -ENODEV, clear);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns the total size of the log's ring buffer */
|
|
||||||
long android_logger_get_log_size(struct logger* logger) {
|
|
||||||
LOGGER_FUNCTION(logger, -ENODEV, getSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
int android_logger_set_log_size(struct logger* logger, unsigned long size) {
|
|
||||||
LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* returns the readable size of the log's ring buffer (that is, amount of the
|
|
||||||
* log consumed)
|
|
||||||
*/
|
|
||||||
long android_logger_get_log_readable_size(struct logger* logger) {
|
|
||||||
LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* returns the logger version
|
|
||||||
*/
|
|
||||||
int android_logger_get_log_version(struct logger* logger) {
|
|
||||||
LOGGER_FUNCTION(logger, 4, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \
|
|
||||||
ssize_t ret = init_transport_context(logger_list); \
|
|
||||||
if (ret < 0) { \
|
|
||||||
return ret; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
ret = (def); \
|
|
||||||
android_log_transport_context* transport_context = &logger_list->transport_context; \
|
|
||||||
if (transport_context->transport && transport_context->transport->func) { \
|
|
||||||
ssize_t retval = (transport_context->transport->func)(logger_list, transport_context, ##args); \
|
|
||||||
if (ret >= 0 || ret == (def)) { \
|
|
||||||
ret = retval; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return ret
|
|
||||||
|
|
||||||
/*
|
|
||||||
* returns statistics
|
|
||||||
*/
|
|
||||||
ssize_t android_logger_get_statistics(struct logger_list* logger_list, char* buf, size_t len) {
|
|
||||||
LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t android_logger_get_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
|
|
||||||
LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int android_logger_set_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
|
|
||||||
LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) {
|
struct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) {
|
||||||
struct logger_list* logger_list;
|
return android_logger_list_alloc_internal(mode, tail, log_time(0, 0), pid);
|
||||||
|
|
||||||
logger_list = static_cast<struct logger_list*>(calloc(1, sizeof(*logger_list)));
|
|
||||||
if (!logger_list) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_init(&logger_list->logger);
|
|
||||||
logger_list->mode = mode;
|
|
||||||
logger_list->tail = tail;
|
|
||||||
logger_list->pid = pid;
|
|
||||||
|
|
||||||
return logger_list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct logger_list* android_logger_list_alloc_time(int mode, log_time start, pid_t pid) {
|
struct logger_list* android_logger_list_alloc_time(int mode, log_time start, pid_t pid) {
|
||||||
struct logger_list* logger_list;
|
return android_logger_list_alloc_internal(mode, 0, start, pid);
|
||||||
|
|
||||||
logger_list = static_cast<struct logger_list*>(calloc(1, sizeof(*logger_list)));
|
|
||||||
if (!logger_list) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_init(&logger_list->logger);
|
|
||||||
logger_list->mode = mode;
|
|
||||||
logger_list->start = start;
|
|
||||||
logger_list->pid = pid;
|
|
||||||
|
|
||||||
return logger_list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* android_logger_list_register unimplemented, no use case */
|
|
||||||
/* android_logger_list_unregister unimplemented, no use case */
|
|
||||||
|
|
||||||
/* Open the named log and add it to the logger list */
|
/* Open the named log and add it to the logger list */
|
||||||
struct logger* android_logger_open(struct logger_list* logger_list, log_id_t logId) {
|
struct logger* android_logger_open(struct logger_list* logger_list, log_id_t logId) {
|
||||||
struct logger* logger;
|
|
||||||
|
|
||||||
if (!logger_list || (logId >= LOG_ID_MAX)) {
|
if (!logger_list || (logId >= LOG_ID_MAX)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger_for_each(logger, logger_list) {
|
logger_list->log_mask |= 1 << logId;
|
||||||
if (logger->logId == logId) {
|
|
||||||
return reinterpret_cast<struct logger*>(logger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger = static_cast<struct logger*>(calloc(1, sizeof(*logger)));
|
uintptr_t logger = logId;
|
||||||
if (!logger) {
|
logger |= (logger_list->mode & ANDROID_LOG_PSTORE) ? LOGGER_PMSG : LOGGER_LOGD;
|
||||||
return nullptr;
|
return reinterpret_cast<struct logger*>(logger);
|
||||||
}
|
|
||||||
|
|
||||||
logger->logId = logId;
|
|
||||||
list_add_tail(&logger_list->logger, &logger->node);
|
|
||||||
logger->parent = logger_list;
|
|
||||||
|
|
||||||
// Reset known transport to re-evaluate, since we added a new logger.
|
|
||||||
logger_list->transport_initialized = false;
|
|
||||||
|
|
||||||
return logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open the single named log and make it part of a new logger list */
|
/* Open the single named log and make it part of a new logger list */
|
||||||
|
|
@ -256,10 +99,14 @@ struct logger_list* android_logger_list_open(log_id_t logId, int mode, unsigned
|
||||||
return logger_list;
|
return logger_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Validate log_msg packet, read function has already been null checked */
|
int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
|
||||||
static int android_transport_read(struct logger_list* logger_list,
|
if (logger_list == nullptr || logger_list->transport_context.transport == nullptr ||
|
||||||
struct android_log_transport_context* transp,
|
logger_list->log_mask == 0) {
|
||||||
struct log_msg* log_msg) {
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
android_log_transport_context* transp = &logger_list->transport_context;
|
||||||
|
|
||||||
int ret = (*transp->transport->read)(logger_list, transp, log_msg);
|
int ret = (*transp->transport->read)(logger_list, transp, log_msg);
|
||||||
|
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
|
|
@ -285,17 +132,6 @@ static int android_transport_read(struct logger_list* logger_list,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read from the selected logs */
|
|
||||||
int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
|
|
||||||
int ret = init_transport_context(logger_list);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
android_log_transport_context* transport_context = &logger_list->transport_context;
|
|
||||||
return android_transport_read(logger_list, transport_context, log_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close all the logs */
|
/* Close all the logs */
|
||||||
void android_logger_list_free(struct logger_list* logger_list) {
|
void android_logger_list_free(struct logger_list* logger_list) {
|
||||||
if (logger_list == NULL) {
|
if (logger_list == NULL) {
|
||||||
|
|
@ -308,11 +144,5 @@ void android_logger_list_free(struct logger_list* logger_list) {
|
||||||
(*transport_context->transport->close)(logger_list, transport_context);
|
(*transport_context->transport->close)(logger_list, transport_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!list_empty(&logger_list->logger)) {
|
|
||||||
struct listnode* node = list_head(&logger_list->logger);
|
|
||||||
struct logger* logger = node_to_item(node, struct logger, node);
|
|
||||||
android_logger_free((struct logger*)logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(logger_list);
|
free(logger_list);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,27 +27,16 @@
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
static int PmsgAvailable(log_id_t logId);
|
static int PmsgAvailable(log_id_t logId);
|
||||||
static int PmsgVersion(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
static int PmsgRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
static int PmsgRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
||||||
struct log_msg* log_msg);
|
struct log_msg* log_msg);
|
||||||
static void PmsgClose(struct logger_list* logger_list,
|
static void PmsgClose(struct logger_list* logger_list,
|
||||||
struct android_log_transport_context* transp);
|
struct android_log_transport_context* transp);
|
||||||
static int PmsgClear(struct logger* logger, struct android_log_transport_context* transp);
|
|
||||||
|
|
||||||
struct android_log_transport_read pmsgLoggerRead = {
|
struct android_log_transport_read pmsgLoggerRead = {
|
||||||
.name = "pmsg",
|
.name = "pmsg",
|
||||||
.available = PmsgAvailable,
|
.available = PmsgAvailable,
|
||||||
.version = PmsgVersion,
|
|
||||||
.close = PmsgClose,
|
.close = PmsgClose,
|
||||||
.read = PmsgRead,
|
.read = PmsgRead,
|
||||||
.poll = NULL,
|
|
||||||
.clear = PmsgClear,
|
|
||||||
.setSize = NULL,
|
|
||||||
.getSize = NULL,
|
|
||||||
.getReadableSize = NULL,
|
|
||||||
.getPrune = NULL,
|
|
||||||
.setPrune = NULL,
|
|
||||||
.getStats = NULL,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int PmsgAvailable(log_id_t logId) {
|
static int PmsgAvailable(log_id_t logId) {
|
||||||
|
|
@ -60,17 +49,6 @@ static int PmsgAvailable(log_id_t logId) {
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PmsgClear(struct logger*, struct android_log_transport_context*) {
|
|
||||||
return unlink("/sys/fs/pstore/pmsg-ramoops-0");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* returns the logger version
|
|
||||||
*/
|
|
||||||
static int PmsgVersion(struct logger*, struct android_log_transport_context*) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int PmsgRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
static int PmsgRead(struct logger_list* logger_list, struct android_log_transport_context* transp,
|
||||||
struct log_msg* log_msg) {
|
struct log_msg* log_msg) {
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
@ -134,7 +112,7 @@ static int PmsgRead(struct logger_list* logger_list, struct android_log_transpor
|
||||||
}
|
}
|
||||||
preread_count = 0;
|
preread_count = 0;
|
||||||
|
|
||||||
if ((transp->logMask & (1 << buf.l.id)) &&
|
if ((logger_list->log_mask & (1 << buf.l.id)) &&
|
||||||
((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
|
((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
|
||||||
((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
|
((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
|
||||||
((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
|
((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
|
||||||
|
|
@ -232,12 +210,12 @@ ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio, const char* pref
|
||||||
memset(&transp, 0, sizeof(transp));
|
memset(&transp, 0, sizeof(transp));
|
||||||
|
|
||||||
logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK | ANDROID_LOG_RDONLY;
|
logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK | ANDROID_LOG_RDONLY;
|
||||||
transp.logMask = (unsigned)-1;
|
logger_list.log_mask = (unsigned)-1;
|
||||||
if (logId != LOG_ID_ANY) {
|
if (logId != LOG_ID_ANY) {
|
||||||
transp.logMask = (1 << logId);
|
logger_list.log_mask = (1 << logId);
|
||||||
}
|
}
|
||||||
transp.logMask &= ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
|
logger_list.log_mask &= ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
|
||||||
if (!transp.logMask) {
|
if (!logger_list.log_mask) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -913,7 +913,7 @@ static void BM_lookupEventTagNum(benchmark::State& state) {
|
||||||
}
|
}
|
||||||
BENCHMARK(BM_lookupEventTagNum);
|
BENCHMARK(BM_lookupEventTagNum);
|
||||||
|
|
||||||
// Must be functionally identical to liblog internal __send_log_msg.
|
// Must be functionally identical to liblog internal SendLogdControlMessage()
|
||||||
static void send_to_control(char* buf, size_t len) {
|
static void send_to_control(char* buf, size_t len) {
|
||||||
int sock =
|
int sock =
|
||||||
socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM | SOCK_CLOEXEC);
|
socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM | SOCK_CLOEXEC);
|
||||||
|
|
|
||||||
|
|
@ -969,6 +969,16 @@ int Logcat::Run(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode & ANDROID_LOG_PSTORE) {
|
||||||
|
if (clearLog) {
|
||||||
|
unlink("/sys/fs/pstore/pmsg-ramoops-0");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
|
||||||
|
LogcatPanic(HELP_TRUE, "-L is incompatible with -g/-G, -S, and -p/-P");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
|
std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
|
||||||
nullptr, &android_logger_list_free};
|
nullptr, &android_logger_list_free};
|
||||||
if (tail_time != log_time::EPOCH) {
|
if (tail_time != log_time::EPOCH) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue