2591 lines
81 KiB
C++
2591 lines
81 KiB
C++
/*
|
|
* Copyright (C) 2013-2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <inttypes.h>
|
|
#include <semaphore.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <cutils/properties.h>
|
|
#include <gtest/gtest.h>
|
|
#include <log/log.h>
|
|
#include <log/logger.h>
|
|
#include <log/log_read.h>
|
|
#include <log/logprint.h>
|
|
#include <private/android_filesystem_config.h>
|
|
#include <private/android_logger.h>
|
|
|
|
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
|
|
// non-syscall libs. Since we are only using this in the emergency of
|
|
// a signal to stuff a terminating code into the logs, we will spin rather
|
|
// than try a usleep.
|
|
#define LOG_FAILURE_RETRY(exp) ({ \
|
|
typeof (exp) _rc; \
|
|
do { \
|
|
_rc = (exp); \
|
|
} while (((_rc == -1) \
|
|
&& ((errno == EINTR) \
|
|
|| (errno == EAGAIN))) \
|
|
|| (_rc == -EINTR) \
|
|
|| (_rc == -EAGAIN)); \
|
|
_rc; })
|
|
|
|
TEST(liblog, __android_log_buf_print) {
|
|
EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
|
|
"TEST__android_log_buf_print",
|
|
"radio"));
|
|
usleep(1000);
|
|
EXPECT_LT(0, __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
|
|
"TEST__android_log_buf_print",
|
|
"system"));
|
|
usleep(1000);
|
|
EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
|
|
"TEST__android_log_buf_print",
|
|
"main"));
|
|
usleep(1000);
|
|
}
|
|
|
|
TEST(liblog, __android_log_buf_write) {
|
|
EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
|
|
"TEST__android_log_buf_write",
|
|
"radio"));
|
|
usleep(1000);
|
|
EXPECT_LT(0, __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
|
|
"TEST__android_log_buf_write",
|
|
"system"));
|
|
usleep(1000);
|
|
EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
|
|
"TEST__android_log_buf_write",
|
|
"main"));
|
|
usleep(1000);
|
|
}
|
|
|
|
TEST(liblog, __android_log_btwrite) {
|
|
int intBuf = 0xDEADBEEF;
|
|
EXPECT_LT(0, __android_log_btwrite(0,
|
|
EVENT_TYPE_INT,
|
|
&intBuf, sizeof(intBuf)));
|
|
long long longBuf = 0xDEADBEEFA55A5AA5;
|
|
EXPECT_LT(0, __android_log_btwrite(0,
|
|
EVENT_TYPE_LONG,
|
|
&longBuf, sizeof(longBuf)));
|
|
usleep(1000);
|
|
char Buf[] = "\20\0\0\0DeAdBeEfA55a5aA5";
|
|
EXPECT_LT(0, __android_log_btwrite(0,
|
|
EVENT_TYPE_STRING,
|
|
Buf, sizeof(Buf) - 1));
|
|
usleep(1000);
|
|
}
|
|
|
|
static void* ConcurrentPrintFn(void *arg) {
|
|
int ret = __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
|
|
"TEST__android_log_print", "Concurrent %" PRIuPTR,
|
|
reinterpret_cast<uintptr_t>(arg));
|
|
return reinterpret_cast<void*>(ret);
|
|
}
|
|
|
|
#define NUM_CONCURRENT 64
|
|
#define _concurrent_name(a,n) a##__concurrent##n
|
|
#define concurrent_name(a,n) _concurrent_name(a,n)
|
|
|
|
TEST(liblog, concurrent_name(__android_log_buf_print, NUM_CONCURRENT)) {
|
|
pthread_t t[NUM_CONCURRENT];
|
|
int i;
|
|
for (i=0; i < NUM_CONCURRENT; i++) {
|
|
ASSERT_EQ(0, pthread_create(&t[i], NULL,
|
|
ConcurrentPrintFn,
|
|
reinterpret_cast<void *>(i)));
|
|
}
|
|
int ret = 0;
|
|
for (i=0; i < NUM_CONCURRENT; i++) {
|
|
void* result;
|
|
ASSERT_EQ(0, pthread_join(t[i], &result));
|
|
int this_result = reinterpret_cast<uintptr_t>(result);
|
|
if ((0 == ret) && (0 != this_result)) {
|
|
ret = this_result;
|
|
}
|
|
}
|
|
ASSERT_LT(0, ret);
|
|
}
|
|
|
|
TEST(liblog, __android_log_btwrite__android_logger_list_read) {
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
log_time ts(CLOCK_MONOTONIC);
|
|
|
|
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
|
|
usleep(1000000);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
ASSERT_EQ(log_msg.entry.pid, pid);
|
|
|
|
if ((log_msg.entry.len != (4 + 1 + 8))
|
|
|| (log_msg.id() != LOG_ID_EVENTS)) {
|
|
continue;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
if (eventData[4] != EVENT_TYPE_LONG) {
|
|
continue;
|
|
}
|
|
|
|
log_time tx(eventData + 4 + 1);
|
|
if (ts == tx) {
|
|
++count;
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
static inline int32_t get4LE(const char* src)
|
|
{
|
|
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
|
}
|
|
|
|
static void bswrite_test(const char *message) {
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
log_time ts(android_log_clockid());
|
|
|
|
ASSERT_LT(0, __android_log_bswrite(0, message));
|
|
size_t num_lines = 1, size = 0, length = 0, total = 0;
|
|
const char *cp = message;
|
|
while (*cp) {
|
|
if (*cp == '\n') {
|
|
if (cp[1]) {
|
|
++num_lines;
|
|
}
|
|
} else {
|
|
++size;
|
|
}
|
|
++cp;
|
|
++total;
|
|
++length;
|
|
if ((LOGGER_ENTRY_MAX_PAYLOAD - 4 - 1 - 4) <= length) {
|
|
break;
|
|
}
|
|
}
|
|
while (*cp) {
|
|
++cp;
|
|
++total;
|
|
}
|
|
usleep(1000000);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
ASSERT_EQ(log_msg.entry.pid, pid);
|
|
|
|
if ((log_msg.entry.sec < (ts.tv_sec - 1))
|
|
|| ((ts.tv_sec + 1) < log_msg.entry.sec)
|
|
|| ((size_t)log_msg.entry.len != (4 + 1 + 4 + length))
|
|
|| (log_msg.id() != LOG_ID_EVENTS)) {
|
|
continue;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
if (eventData[4] != EVENT_TYPE_STRING) {
|
|
continue;
|
|
}
|
|
|
|
size_t len = get4LE(eventData + 4 + 1);
|
|
if (len == total) {
|
|
++count;
|
|
|
|
AndroidLogFormat *logformat = android_log_format_new();
|
|
EXPECT_TRUE(NULL != logformat);
|
|
AndroidLogEntry entry;
|
|
char msgBuf[1024];
|
|
int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
|
|
&log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
|
|
EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
|
|
if (processBinaryLogBuffer == 0) {
|
|
fflush(stderr);
|
|
EXPECT_EQ((int)((20 * num_lines) + size),
|
|
android_log_printLogLine(logformat, fileno(stderr), &entry));
|
|
}
|
|
android_log_format_free(logformat);
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, __android_log_bswrite_and_print) {
|
|
bswrite_test("Hello World");
|
|
}
|
|
|
|
TEST(liblog, __android_log_bswrite_and_print__empty_string) {
|
|
bswrite_test("");
|
|
}
|
|
|
|
TEST(liblog, __android_log_bswrite_and_print__newline_prefix) {
|
|
bswrite_test("\nHello World\n");
|
|
}
|
|
|
|
TEST(liblog, __android_log_bswrite_and_print__newline_space_prefix) {
|
|
bswrite_test("\n Hello World \n");
|
|
}
|
|
|
|
TEST(liblog, __android_log_bswrite_and_print__multiple_newline) {
|
|
bswrite_test("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
|
|
}
|
|
|
|
static void buf_write_test(const char *message) {
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
static const char tag[] = "TEST__android_log_buf_write";
|
|
log_time ts(android_log_clockid());
|
|
|
|
EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
|
|
tag, message));
|
|
size_t num_lines = 1, size = 0, length = 0;
|
|
const char *cp = message;
|
|
while (*cp) {
|
|
if (*cp == '\n') {
|
|
if (cp[1]) {
|
|
++num_lines;
|
|
}
|
|
} else {
|
|
++size;
|
|
}
|
|
++length;
|
|
if ((LOGGER_ENTRY_MAX_PAYLOAD - 2 - sizeof(tag)) <= length) {
|
|
break;
|
|
}
|
|
++cp;
|
|
}
|
|
usleep(1000000);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
ASSERT_EQ(log_msg.entry.pid, pid);
|
|
|
|
if ((log_msg.entry.sec < (ts.tv_sec - 1))
|
|
|| ((ts.tv_sec + 1) < log_msg.entry.sec)
|
|
|| ((size_t)log_msg.entry.len != (sizeof(tag) + length + 2))
|
|
|| (log_msg.id() != LOG_ID_MAIN)) {
|
|
continue;
|
|
}
|
|
|
|
++count;
|
|
|
|
AndroidLogFormat *logformat = android_log_format_new();
|
|
EXPECT_TRUE(NULL != logformat);
|
|
AndroidLogEntry entry;
|
|
int processLogBuffer = android_log_processLogBuffer(&log_msg.entry_v1,
|
|
&entry);
|
|
EXPECT_EQ(0, processLogBuffer);
|
|
if (processLogBuffer == 0) {
|
|
fflush(stderr);
|
|
EXPECT_EQ((int)(((11 + sizeof(tag)) * num_lines) + size),
|
|
android_log_printLogLine(logformat, fileno(stderr), &entry));
|
|
}
|
|
android_log_format_free(logformat);
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, __android_log_buf_write_and_print__empty) {
|
|
buf_write_test("");
|
|
}
|
|
|
|
TEST(liblog, __android_log_buf_write_and_print__newline_prefix) {
|
|
buf_write_test("\nHello World\n");
|
|
}
|
|
|
|
TEST(liblog, __android_log_buf_write_and_print__newline_space_prefix) {
|
|
buf_write_test("\n Hello World \n");
|
|
}
|
|
|
|
TEST(liblog, __security) {
|
|
static const char persist_key[] = "persist.logd.security";
|
|
static const char readonly_key[] = "ro.device_owner";
|
|
static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
|
|
char persist[PROP_VALUE_MAX];
|
|
char readonly[PROP_VALUE_MAX];
|
|
|
|
property_get(persist_key, persist, "");
|
|
property_get(readonly_key, readonly, nothing_val);
|
|
|
|
if (!strcmp(readonly, nothing_val)) {
|
|
EXPECT_FALSE(__android_log_security());
|
|
fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
|
|
property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
|
|
} else if (!strcasecmp(readonly, "false") || !readonly[0]) {
|
|
EXPECT_FALSE(__android_log_security());
|
|
return;
|
|
}
|
|
|
|
if (!strcasecmp(persist, "true")) {
|
|
EXPECT_TRUE(__android_log_security());
|
|
} else {
|
|
EXPECT_FALSE(__android_log_security());
|
|
}
|
|
property_set(persist_key, "TRUE");
|
|
EXPECT_TRUE(__android_log_security());
|
|
property_set(persist_key, "FALSE");
|
|
EXPECT_FALSE(__android_log_security());
|
|
property_set(persist_key, "true");
|
|
EXPECT_TRUE(__android_log_security());
|
|
property_set(persist_key, "false");
|
|
EXPECT_FALSE(__android_log_security());
|
|
property_set(persist_key, "");
|
|
EXPECT_FALSE(__android_log_security());
|
|
property_set(persist_key, persist);
|
|
}
|
|
|
|
TEST(liblog, __security_buffer) {
|
|
struct logger_list *logger_list;
|
|
android_event_long_t buffer;
|
|
|
|
static const char persist_key[] = "persist.logd.security";
|
|
char persist[PROP_VALUE_MAX];
|
|
bool set_persist = false;
|
|
bool allow_security = false;
|
|
|
|
if (__android_log_security()) {
|
|
allow_security = true;
|
|
} else {
|
|
property_get(persist_key, persist, "");
|
|
if (strcasecmp(persist, "true")) {
|
|
property_set(persist_key, "TRUE");
|
|
if (__android_log_security()) {
|
|
allow_security = true;
|
|
set_persist = true;
|
|
} else {
|
|
property_set(persist_key, persist);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!allow_security) {
|
|
fprintf(stderr, "WARNING: "
|
|
"security buffer disabled, bypassing end-to-end test\n");
|
|
|
|
log_time ts(CLOCK_MONOTONIC);
|
|
|
|
buffer.type = EVENT_TYPE_LONG;
|
|
buffer.data = *(static_cast<uint64_t *>((void *)&ts));
|
|
|
|
// expect failure!
|
|
ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
|
|
|
|
return;
|
|
}
|
|
|
|
/* Matches clientHasLogCredentials() in logd */
|
|
uid_t uid = getuid();
|
|
gid_t gid = getgid();
|
|
bool clientHasLogCredentials = true;
|
|
if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)
|
|
&& (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
|
|
uid_t euid = geteuid();
|
|
if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
|
|
gid_t egid = getegid();
|
|
if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
|
|
int num_groups = getgroups(0, NULL);
|
|
if (num_groups > 0) {
|
|
gid_t groups[num_groups];
|
|
num_groups = getgroups(num_groups, groups);
|
|
while (num_groups > 0) {
|
|
if (groups[num_groups - 1] == AID_LOG) {
|
|
break;
|
|
}
|
|
--num_groups;
|
|
}
|
|
}
|
|
if (num_groups <= 0) {
|
|
clientHasLogCredentials = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!clientHasLogCredentials) {
|
|
fprintf(stderr, "WARNING: "
|
|
"not in system context, bypassing end-to-end test\n");
|
|
|
|
log_time ts(CLOCK_MONOTONIC);
|
|
|
|
buffer.type = EVENT_TYPE_LONG;
|
|
buffer.data = *(static_cast<uint64_t *>((void *)&ts));
|
|
|
|
// expect failure!
|
|
ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
|
|
|
|
return;
|
|
}
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
|
|
1000, pid)));
|
|
|
|
log_time ts(CLOCK_MONOTONIC);
|
|
|
|
buffer.type = EVENT_TYPE_LONG;
|
|
buffer.data = *(static_cast<uint64_t *>((void *)&ts));
|
|
|
|
ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
|
|
usleep(1000000);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
ASSERT_EQ(log_msg.entry.pid, pid);
|
|
|
|
if ((log_msg.entry.len != (4 + 1 + 8))
|
|
|| (log_msg.id() != LOG_ID_SECURITY)) {
|
|
continue;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
if (eventData[4] != EVENT_TYPE_LONG) {
|
|
continue;
|
|
}
|
|
|
|
log_time tx(eventData + 4 + 1);
|
|
if (ts == tx) {
|
|
++count;
|
|
}
|
|
}
|
|
|
|
if (set_persist) {
|
|
property_set(persist_key, persist);
|
|
}
|
|
|
|
android_logger_list_close(logger_list);
|
|
|
|
bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
|
|
if (!clientHasSecurityCredentials) {
|
|
fprintf(stderr, "WARNING: "
|
|
"not system, content submitted but can not check end-to-end\n");
|
|
}
|
|
EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
|
|
|
|
}
|
|
|
|
static unsigned signaled;
|
|
static log_time signal_time;
|
|
|
|
/*
|
|
* Strictly, we are not allowed to log messages in a signal context, but we
|
|
* do make an effort to keep the failure surface minimized, and this in-effect
|
|
* should catch any regressions in that effort. The odds of a logged message
|
|
* in a signal handler causing a lockup problem should be _very_ small.
|
|
*/
|
|
static void caught_blocking_signal(int /*signum*/)
|
|
{
|
|
unsigned long long v = 0xDEADBEEFA55A0000ULL;
|
|
|
|
v += getpid() & 0xFFFF;
|
|
|
|
++signaled;
|
|
if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
|
|
signal_time = log_time(CLOCK_MONOTONIC);
|
|
signal_time.tv_sec += 2;
|
|
}
|
|
|
|
LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
|
|
}
|
|
|
|
// Fill in current process user and system time in 10ms increments
|
|
static void get_ticks(unsigned long long *uticks, unsigned long long *sticks)
|
|
{
|
|
*uticks = *sticks = 0;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
char buffer[512];
|
|
snprintf(buffer, sizeof(buffer), "/proc/%u/stat", pid);
|
|
|
|
FILE *fp = fopen(buffer, "r");
|
|
if (!fp) {
|
|
return;
|
|
}
|
|
|
|
char *cp = fgets(buffer, sizeof(buffer), fp);
|
|
fclose(fp);
|
|
if (!cp) {
|
|
return;
|
|
}
|
|
|
|
pid_t d;
|
|
char s[sizeof(buffer)];
|
|
char c;
|
|
long long ll;
|
|
unsigned long long ull;
|
|
|
|
if (15 != sscanf(buffer,
|
|
"%d %s %c %lld %lld %lld %lld %lld %llu %llu %llu %llu %llu %llu %llu ",
|
|
&d, s, &c, &ll, &ll, &ll, &ll, &ll, &ull, &ull, &ull, &ull, &ull,
|
|
uticks, sticks)) {
|
|
*uticks = *sticks = 0;
|
|
}
|
|
}
|
|
|
|
TEST(liblog, android_logger_list_read__cpu_signal) {
|
|
struct logger_list *logger_list;
|
|
unsigned long long v = 0xDEADBEEFA55A0000ULL;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
v += pid & 0xFFFF;
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
|
|
|
|
int count = 0;
|
|
|
|
int signals = 0;
|
|
|
|
unsigned long long uticks_start;
|
|
unsigned long long sticks_start;
|
|
get_ticks(&uticks_start, &sticks_start);
|
|
|
|
const unsigned alarm_time = 10;
|
|
|
|
memset(&signal_time, 0, sizeof(signal_time));
|
|
|
|
signal(SIGALRM, caught_blocking_signal);
|
|
alarm(alarm_time);
|
|
|
|
signaled = 0;
|
|
|
|
do {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
alarm(alarm_time);
|
|
|
|
++count;
|
|
|
|
ASSERT_EQ(log_msg.entry.pid, pid);
|
|
|
|
if ((log_msg.entry.len != (4 + 1 + 8))
|
|
|| (log_msg.id() != LOG_ID_EVENTS)) {
|
|
continue;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
if (eventData[4] != EVENT_TYPE_LONG) {
|
|
continue;
|
|
}
|
|
|
|
unsigned long long l = eventData[4 + 1 + 0] & 0xFF;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 1] & 0xFF) << 8;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 2] & 0xFF) << 16;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 3] & 0xFF) << 24;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 4] & 0xFF) << 32;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 5] & 0xFF) << 40;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 6] & 0xFF) << 48;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 7] & 0xFF) << 56;
|
|
|
|
if (l == v) {
|
|
++signals;
|
|
break;
|
|
}
|
|
} while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
|
|
alarm(0);
|
|
signal(SIGALRM, SIG_DFL);
|
|
|
|
EXPECT_LE(1, count);
|
|
|
|
EXPECT_EQ(1, signals);
|
|
|
|
android_logger_list_close(logger_list);
|
|
|
|
unsigned long long uticks_end;
|
|
unsigned long long sticks_end;
|
|
get_ticks(&uticks_end, &sticks_end);
|
|
|
|
// Less than 1% in either user or system time, or both
|
|
const unsigned long long one_percent_ticks = alarm_time;
|
|
unsigned long long user_ticks = uticks_end - uticks_start;
|
|
unsigned long long system_ticks = sticks_end - sticks_start;
|
|
EXPECT_GT(one_percent_ticks, user_ticks);
|
|
EXPECT_GT(one_percent_ticks, system_ticks);
|
|
EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
|
|
}
|
|
|
|
/*
|
|
* Strictly, we are not allowed to log messages in a signal context, the
|
|
* correct way to handle this is to ensure the messages are constructed in
|
|
* a thread; the signal handler should only unblock the thread.
|
|
*/
|
|
static sem_t thread_trigger;
|
|
|
|
static void caught_blocking_thread(int /*signum*/)
|
|
{
|
|
sem_post(&thread_trigger);
|
|
}
|
|
|
|
static void *running_thread(void *) {
|
|
unsigned long long v = 0xDEADBEAFA55A0000ULL;
|
|
|
|
v += getpid() & 0xFFFF;
|
|
|
|
struct timespec timeout;
|
|
clock_gettime(CLOCK_REALTIME, &timeout);
|
|
timeout.tv_sec += 55;
|
|
sem_timedwait(&thread_trigger, &timeout);
|
|
|
|
++signaled;
|
|
if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
|
|
signal_time = log_time(CLOCK_MONOTONIC);
|
|
signal_time.tv_sec += 2;
|
|
}
|
|
|
|
LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int start_thread()
|
|
{
|
|
sem_init(&thread_trigger, 0, 0);
|
|
|
|
pthread_attr_t attr;
|
|
if (pthread_attr_init(&attr)) {
|
|
return -1;
|
|
}
|
|
|
|
struct sched_param param;
|
|
|
|
memset(¶m, 0, sizeof(param));
|
|
pthread_attr_setschedparam(&attr, ¶m);
|
|
pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
|
|
|
|
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
|
|
pthread_attr_destroy(&attr);
|
|
return -1;
|
|
}
|
|
|
|
pthread_t thread;
|
|
if (pthread_create(&thread, &attr, running_thread, NULL)) {
|
|
pthread_attr_destroy(&attr);
|
|
return -1;
|
|
}
|
|
|
|
pthread_attr_destroy(&attr);
|
|
return 0;
|
|
}
|
|
|
|
TEST(liblog, android_logger_list_read__cpu_thread) {
|
|
struct logger_list *logger_list;
|
|
unsigned long long v = 0xDEADBEAFA55A0000ULL;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
v += pid & 0xFFFF;
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
|
|
|
|
int count = 0;
|
|
|
|
int signals = 0;
|
|
|
|
unsigned long long uticks_start;
|
|
unsigned long long sticks_start;
|
|
get_ticks(&uticks_start, &sticks_start);
|
|
|
|
const unsigned alarm_time = 10;
|
|
|
|
memset(&signal_time, 0, sizeof(signal_time));
|
|
|
|
signaled = 0;
|
|
EXPECT_EQ(0, start_thread());
|
|
|
|
signal(SIGALRM, caught_blocking_thread);
|
|
alarm(alarm_time);
|
|
|
|
do {
|
|
log_msg log_msg;
|
|
if (LOG_FAILURE_RETRY(android_logger_list_read(logger_list, &log_msg)) <= 0) {
|
|
break;
|
|
}
|
|
|
|
alarm(alarm_time);
|
|
|
|
++count;
|
|
|
|
ASSERT_EQ(log_msg.entry.pid, pid);
|
|
|
|
if ((log_msg.entry.len != (4 + 1 + 8))
|
|
|| (log_msg.id() != LOG_ID_EVENTS)) {
|
|
continue;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
if (eventData[4] != EVENT_TYPE_LONG) {
|
|
continue;
|
|
}
|
|
|
|
unsigned long long l = eventData[4 + 1 + 0] & 0xFF;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 1] & 0xFF) << 8;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 2] & 0xFF) << 16;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 3] & 0xFF) << 24;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 4] & 0xFF) << 32;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 5] & 0xFF) << 40;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 6] & 0xFF) << 48;
|
|
l |= (unsigned long long) (eventData[4 + 1 + 7] & 0xFF) << 56;
|
|
|
|
if (l == v) {
|
|
++signals;
|
|
break;
|
|
}
|
|
} while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
|
|
alarm(0);
|
|
signal(SIGALRM, SIG_DFL);
|
|
|
|
EXPECT_LE(1, count);
|
|
|
|
EXPECT_EQ(1, signals);
|
|
|
|
android_logger_list_close(logger_list);
|
|
|
|
unsigned long long uticks_end;
|
|
unsigned long long sticks_end;
|
|
get_ticks(&uticks_end, &sticks_end);
|
|
|
|
// Less than 1% in either user or system time, or both
|
|
const unsigned long long one_percent_ticks = alarm_time;
|
|
unsigned long long user_ticks = uticks_end - uticks_start;
|
|
unsigned long long system_ticks = sticks_end - sticks_start;
|
|
EXPECT_GT(one_percent_ticks, user_ticks);
|
|
EXPECT_GT(one_percent_ticks, system_ticks);
|
|
EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
|
|
}
|
|
|
|
static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
|
|
#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
|
|
sizeof(max_payload_tag) - 1)
|
|
static const char max_payload_buf[] = "LEONATO\n\
|
|
I learn in this letter that Don Peter of Arragon\n\
|
|
comes this night to Messina\n\
|
|
MESSENGER\n\
|
|
He is very near by this: he was not three leagues off\n\
|
|
when I left him\n\
|
|
LEONATO\n\
|
|
How many gentlemen have you lost in this action?\n\
|
|
MESSENGER\n\
|
|
But few of any sort, and none of name\n\
|
|
LEONATO\n\
|
|
A victory is twice itself when the achiever brings\n\
|
|
home full numbers. I find here that Don Peter hath\n\
|
|
bestowed much honour on a young Florentine called Claudio\n\
|
|
MESSENGER\n\
|
|
Much deserved on his part and equally remembered by\n\
|
|
Don Pedro: he hath borne himself beyond the\n\
|
|
promise of his age, doing, in the figure of a lamb,\n\
|
|
the feats of a lion: he hath indeed better\n\
|
|
bettered expectation than you must expect of me to\n\
|
|
tell you how\n\
|
|
LEONATO\n\
|
|
He hath an uncle here in Messina will be very much\n\
|
|
glad of it.\n\
|
|
MESSENGER\n\
|
|
I have already delivered him letters, and there\n\
|
|
appears much joy in him; even so much that joy could\n\
|
|
not show itself modest enough without a badge of\n\
|
|
bitterness.\n\
|
|
LEONATO\n\
|
|
Did he break out into tears?\n\
|
|
MESSENGER\n\
|
|
In great measure.\n\
|
|
LEONATO\n\
|
|
A kind overflow of kindness: there are no faces\n\
|
|
truer than those that are so washed. How much\n\
|
|
better is it to weep at joy than to joy at weeping!\n\
|
|
BEATRICE\n\
|
|
I pray you, is Signior Mountanto returned from the\n\
|
|
wars or no?\n\
|
|
MESSENGER\n\
|
|
I know none of that name, lady: there was none such\n\
|
|
in the army of any sort.\n\
|
|
LEONATO\n\
|
|
What is he that you ask for, niece?\n\
|
|
HERO\n\
|
|
My cousin means Signior Benedick of Padua.\n\
|
|
MESSENGER\n\
|
|
O, he's returned; and as pleasant as ever he was.\n\
|
|
BEATRICE\n\
|
|
He set up his bills here in Messina and challenged\n\
|
|
Cupid at the flight; and my uncle's fool, reading\n\
|
|
the challenge, subscribed for Cupid, and challenged\n\
|
|
him at the bird-bolt. I pray you, how many hath he\n\
|
|
killed and eaten in these wars? But how many hath\n\
|
|
he killed? for indeed I promised to eat all of his killing.\n\
|
|
LEONATO\n\
|
|
Faith, niece, you tax Signior Benedick too much;\n\
|
|
but he'll be meet with you, I doubt it not.\n\
|
|
MESSENGER\n\
|
|
He hath done good service, lady, in these wars.\n\
|
|
BEATRICE\n\
|
|
You had musty victual, and he hath holp to eat it:\n\
|
|
he is a very valiant trencherman; he hath an\n\
|
|
excellent stomach.\n\
|
|
MESSENGER\n\
|
|
And a good soldier too, lady.\n\
|
|
BEATRICE\n\
|
|
And a good soldier to a lady: but what is he to a lord?\n\
|
|
MESSENGER\n\
|
|
A lord to a lord, a man to a man; stuffed with all\n\
|
|
honourable virtues.\n\
|
|
BEATRICE\n\
|
|
It is so, indeed; he is no less than a stuffed man:\n\
|
|
but for the stuffing,--well, we are all mortal.\n\
|
|
LEONATO\n\
|
|
You must not, sir, mistake my niece. There is a\n\
|
|
kind of merry war betwixt Signior Benedick and her:\n\
|
|
they never meet but there's a skirmish of wit\n\
|
|
between them.\n\
|
|
BEATRICE\n\
|
|
Alas! he gets nothing by that. In our last\n\
|
|
conflict four of his five wits went halting off, and\n\
|
|
now is the whole man governed with one: so that if\n\
|
|
he have wit enough to keep himself warm, let him\n\
|
|
bear it for a difference between himself and his\n\
|
|
horse; for it is all the wealth that he hath left,\n\
|
|
to be known a reasonable creature. Who is his\n\
|
|
companion now? He hath every month a new sworn brother.\n\
|
|
MESSENGER\n\
|
|
Is't possible?\n\
|
|
BEATRICE\n\
|
|
Very easily possible: he wears his faith but as\n\
|
|
the fashion of his hat; it ever changes with the\n\
|
|
next block.\n\
|
|
MESSENGER\n\
|
|
I see, lady, the gentleman is not in your books.\n\
|
|
BEATRICE\n\
|
|
No; an he were, I would burn my study. But, I pray\n\
|
|
you, who is his companion? Is there no young\n\
|
|
squarer now that will make a voyage with him to the devil?\n\
|
|
MESSENGER\n\
|
|
He is most in the company of the right noble Claudio.\n\
|
|
BEATRICE\n\
|
|
O Lord, he will hang upon him like a disease: he\n\
|
|
is sooner caught than the pestilence, and the taker\n\
|
|
runs presently mad. God help the noble Claudio! if\n\
|
|
he have caught the Benedick, it will cost him a\n\
|
|
thousand pound ere a' be cured.\n\
|
|
MESSENGER\n\
|
|
I will hold friends with you, lady.\n\
|
|
BEATRICE\n\
|
|
Do, good friend.\n\
|
|
LEONATO\n\
|
|
You will never run mad, niece.\n\
|
|
BEATRICE\n\
|
|
No, not till a hot January.\n\
|
|
MESSENGER\n\
|
|
Don Pedro is approached.\n\
|
|
Enter DON PEDRO, DON JOHN, CLAUDIO, BENEDICK, and BALTHASAR\n\
|
|
\n\
|
|
DON PEDRO\n\
|
|
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,\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();
|
|
char tag[sizeof(max_payload_tag)];
|
|
memcpy(tag, max_payload_tag, sizeof(tag));
|
|
snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
|
|
|
|
LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
|
|
tag, max_payload_buf));
|
|
sleep(2);
|
|
|
|
struct logger_list *logger_list;
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_SYSTEM, ANDROID_LOG_RDONLY, 100, 0)));
|
|
|
|
bool matches = false;
|
|
ssize_t max_len = 0;
|
|
|
|
for(;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
|
|
continue;
|
|
}
|
|
|
|
char *data = log_msg.msg() + 1;
|
|
|
|
if (strcmp(data, tag)) {
|
|
continue;
|
|
}
|
|
|
|
data += strlen(data) + 1;
|
|
|
|
const char *left = data;
|
|
const char *right = max_payload_buf;
|
|
while (*left && *right && (*left == *right)) {
|
|
++left;
|
|
++right;
|
|
}
|
|
|
|
if (max_len <= (left - data)) {
|
|
max_len = left - data + 1;
|
|
}
|
|
|
|
if (max_len > 512) {
|
|
matches = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
android_logger_list_close(logger_list);
|
|
|
|
EXPECT_EQ(true, matches);
|
|
|
|
EXPECT_LE(SIZEOF_MAX_PAYLOAD_BUF, static_cast<size_t>(max_len));
|
|
}
|
|
|
|
TEST(liblog, __android_log_buf_print__maxtag) {
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
log_time ts(android_log_clockid());
|
|
|
|
EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
|
|
max_payload_buf, max_payload_buf));
|
|
usleep(1000000);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
ASSERT_EQ(log_msg.entry.pid, pid);
|
|
|
|
if ((log_msg.entry.sec < (ts.tv_sec - 1))
|
|
|| ((ts.tv_sec + 1) < log_msg.entry.sec)
|
|
|| ((size_t)log_msg.entry.len < LOGGER_ENTRY_MAX_PAYLOAD)
|
|
|| (log_msg.id() != LOG_ID_MAIN)) {
|
|
continue;
|
|
}
|
|
|
|
++count;
|
|
|
|
AndroidLogFormat *logformat = android_log_format_new();
|
|
EXPECT_TRUE(NULL != logformat);
|
|
AndroidLogEntry entry;
|
|
int processLogBuffer = android_log_processLogBuffer(&log_msg.entry_v1,
|
|
&entry);
|
|
EXPECT_EQ(0, processLogBuffer);
|
|
if (processLogBuffer == 0) {
|
|
fflush(stderr);
|
|
int printLogLine =
|
|
android_log_printLogLine(logformat, fileno(stderr), &entry);
|
|
// Legacy tag truncation
|
|
EXPECT_LE(128, printLogLine);
|
|
// Measured maximum if we try to print part of the tag as message
|
|
EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD * 13 / 8, printLogLine);
|
|
}
|
|
android_log_format_free(logformat);
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, too_big_payload) {
|
|
pid_t pid = getpid();
|
|
static const char big_payload_tag[] = "TEST_big_payload_XXXX";
|
|
char tag[sizeof(big_payload_tag)];
|
|
memcpy(tag, big_payload_tag, sizeof(tag));
|
|
snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
|
|
|
|
std::string longString(3266519, 'x');
|
|
|
|
ssize_t ret = LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM,
|
|
ANDROID_LOG_INFO, tag, longString.c_str()));
|
|
|
|
struct logger_list *logger_list;
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_SYSTEM, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 100, 0)));
|
|
|
|
ssize_t max_len = 0;
|
|
|
|
for(;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
|
|
continue;
|
|
}
|
|
|
|
char *data = log_msg.msg() + 1;
|
|
|
|
if (strcmp(data, tag)) {
|
|
continue;
|
|
}
|
|
|
|
data += strlen(data) + 1;
|
|
|
|
const char *left = data;
|
|
const char *right = longString.c_str();
|
|
while (*left && *right && (*left == *right)) {
|
|
++left;
|
|
++right;
|
|
}
|
|
|
|
if (max_len <= (left - data)) {
|
|
max_len = left - data + 1;
|
|
}
|
|
}
|
|
|
|
android_logger_list_close(logger_list);
|
|
|
|
EXPECT_LE(LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag),
|
|
static_cast<size_t>(max_len));
|
|
|
|
EXPECT_EQ(ret, max_len + static_cast<ssize_t>(sizeof(big_payload_tag)));
|
|
}
|
|
|
|
TEST(liblog, dual_reader) {
|
|
struct logger_list *logger_list1;
|
|
|
|
// >25 messages due to liblog.__android_log_buf_print__concurrentXX above.
|
|
ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open(
|
|
LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 25, 0)));
|
|
|
|
struct logger_list *logger_list2;
|
|
|
|
if (NULL == (logger_list2 = android_logger_list_open(
|
|
LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 15, 0))) {
|
|
android_logger_list_close(logger_list1);
|
|
ASSERT_TRUE(NULL != logger_list2);
|
|
}
|
|
|
|
int count1 = 0;
|
|
bool done1 = false;
|
|
int count2 = 0;
|
|
bool done2 = false;
|
|
|
|
do {
|
|
log_msg log_msg;
|
|
|
|
if (!done1) {
|
|
if (android_logger_list_read(logger_list1, &log_msg) <= 0) {
|
|
done1 = true;
|
|
} else {
|
|
++count1;
|
|
}
|
|
}
|
|
|
|
if (!done2) {
|
|
if (android_logger_list_read(logger_list2, &log_msg) <= 0) {
|
|
done2 = true;
|
|
} else {
|
|
++count2;
|
|
}
|
|
}
|
|
} while ((!done1) || (!done2));
|
|
|
|
android_logger_list_close(logger_list1);
|
|
android_logger_list_close(logger_list2);
|
|
|
|
EXPECT_EQ(25, count1);
|
|
EXPECT_EQ(15, count2);
|
|
}
|
|
|
|
TEST(liblog, android_logger_get_) {
|
|
struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
|
|
|
|
for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
|
|
log_id_t id = static_cast<log_id_t>(i);
|
|
const char *name = android_log_id_to_name(id);
|
|
if (id != android_name_to_log_id(name)) {
|
|
continue;
|
|
}
|
|
fprintf(stderr, "log buffer %s\r", name);
|
|
struct logger * logger;
|
|
EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
|
|
EXPECT_EQ(id, android_logger_get_id(logger));
|
|
ssize_t get_log_size = android_logger_get_log_size(logger);
|
|
/* security buffer is allowed to be denied */
|
|
if (strcmp("security", name)) {
|
|
EXPECT_LT(0, get_log_size);
|
|
/* crash buffer is allowed to be empty, that is actually healthy! */
|
|
EXPECT_LE((strcmp("crash", name)) != 0,
|
|
android_logger_get_log_readable_size(logger));
|
|
} else {
|
|
EXPECT_NE(0, get_log_size);
|
|
if (get_log_size < 0) {
|
|
EXPECT_GT(0, android_logger_get_log_readable_size(logger));
|
|
} else {
|
|
EXPECT_LE(0, android_logger_get_log_readable_size(logger));
|
|
}
|
|
}
|
|
EXPECT_LT(0, android_logger_get_log_version(logger));
|
|
}
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
static bool checkPriForTag(AndroidLogFormat *p_format, const char *tag, android_LogPriority pri) {
|
|
return android_log_shouldPrintLine(p_format, tag, pri)
|
|
&& !android_log_shouldPrintLine(p_format, tag, (android_LogPriority)(pri - 1));
|
|
}
|
|
|
|
TEST(liblog, filterRule) {
|
|
static const char tag[] = "random";
|
|
|
|
AndroidLogFormat *p_format = android_log_format_new();
|
|
|
|
android_log_addFilterRule(p_format,"*:i");
|
|
|
|
EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
|
|
android_log_addFilterRule(p_format, "*");
|
|
EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
|
|
android_log_addFilterRule(p_format, "*:v");
|
|
EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
|
|
android_log_addFilterRule(p_format, "*:i");
|
|
EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
|
|
|
|
android_log_addFilterRule(p_format, tag);
|
|
EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
|
|
android_log_addFilterRule(p_format, "random:v");
|
|
EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
|
|
android_log_addFilterRule(p_format, "random:d");
|
|
EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
|
|
android_log_addFilterRule(p_format, "random:w");
|
|
EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
|
|
|
|
android_log_addFilterRule(p_format, "crap:*");
|
|
EXPECT_TRUE (checkPriForTag(p_format, "crap", ANDROID_LOG_VERBOSE));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
|
|
|
|
// invalid expression
|
|
EXPECT_TRUE (android_log_addFilterRule(p_format, "random:z") < 0);
|
|
EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
|
|
EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
|
|
|
|
// Issue #550946
|
|
EXPECT_TRUE(android_log_addFilterString(p_format, " ") == 0);
|
|
EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
|
|
|
|
// note trailing space
|
|
EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:d ") == 0);
|
|
EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
|
|
|
|
EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:z") < 0);
|
|
|
|
#if 0 // bitrot, seek update
|
|
char defaultBuffer[512];
|
|
|
|
android_log_formatLogLine(p_format,
|
|
defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
|
|
123, 123, tag, "nofile", strlen("Hello"), "Hello", NULL);
|
|
|
|
fprintf(stderr, "%s\n", defaultBuffer);
|
|
#endif
|
|
|
|
android_log_format_free(p_format);
|
|
}
|
|
|
|
TEST(liblog, is_loggable) {
|
|
static const char tag[] = "is_loggable";
|
|
static const char log_namespace[] = "persist.log.tag.";
|
|
static const size_t base_offset = 8; /* skip "persist." */
|
|
// sizeof("string") = strlen("string") + 1
|
|
char key[sizeof(log_namespace) + sizeof(tag) - 1];
|
|
char hold[4][PROP_VALUE_MAX];
|
|
static const struct {
|
|
int level;
|
|
char type;
|
|
} levels[] = {
|
|
{ ANDROID_LOG_VERBOSE, 'v' },
|
|
{ ANDROID_LOG_DEBUG , 'd' },
|
|
{ ANDROID_LOG_INFO , 'i' },
|
|
{ ANDROID_LOG_WARN , 'w' },
|
|
{ ANDROID_LOG_ERROR , 'e' },
|
|
{ ANDROID_LOG_FATAL , 'a' },
|
|
{ -1 , 's' },
|
|
{ -2 , 'g' }, // Illegal value, resort to default
|
|
};
|
|
|
|
// Set up initial test condition
|
|
memset(hold, 0, sizeof(hold));
|
|
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
|
|
property_get(key, hold[0], "");
|
|
property_set(key, "");
|
|
property_get(key + base_offset, hold[1], "");
|
|
property_set(key + base_offset, "");
|
|
strcpy(key, log_namespace);
|
|
key[sizeof(log_namespace) - 2] = '\0';
|
|
property_get(key, hold[2], "");
|
|
property_set(key, "");
|
|
property_get(key, hold[3], "");
|
|
property_set(key + base_offset, "");
|
|
|
|
// All combinations of level and defaults
|
|
for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
|
|
if (levels[i].level == -2) {
|
|
continue;
|
|
}
|
|
for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
|
|
if (levels[j].level == -2) {
|
|
continue;
|
|
}
|
|
fprintf(stderr, "i=%zu j=%zu\r", i, j);
|
|
bool android_log_is_loggable = __android_log_is_loggable(
|
|
levels[i].level, tag, levels[j].level);
|
|
if ((levels[i].level < levels[j].level)
|
|
|| (levels[j].level == -1)) {
|
|
if (android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_FALSE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_FALSE(__android_log_is_loggable(
|
|
levels[i].level, tag, levels[j].level));
|
|
}
|
|
} else {
|
|
if (!android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_TRUE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_TRUE(__android_log_is_loggable(
|
|
levels[i].level, tag, levels[j].level));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// All combinations of level and tag and global properties
|
|
for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
|
|
if (levels[i].level == -2) {
|
|
continue;
|
|
}
|
|
for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
|
|
char buf[2];
|
|
buf[0] = levels[j].type;
|
|
buf[1] = '\0';
|
|
|
|
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
|
|
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
|
|
i, j, key, buf);
|
|
usleep(20000);
|
|
property_set(key, buf);
|
|
bool android_log_is_loggable = __android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG);
|
|
if ((levels[i].level < levels[j].level)
|
|
|| (levels[j].level == -1)
|
|
|| ((levels[i].level < ANDROID_LOG_DEBUG)
|
|
&& (levels[j].level == -2))) {
|
|
if (android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_FALSE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_FALSE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
} else {
|
|
if (!android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_TRUE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_TRUE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
}
|
|
usleep(20000);
|
|
property_set(key, "");
|
|
|
|
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
|
|
i, j, key + base_offset, buf);
|
|
property_set(key + base_offset, buf);
|
|
android_log_is_loggable = __android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG);
|
|
if ((levels[i].level < levels[j].level)
|
|
|| (levels[j].level == -1)
|
|
|| ((levels[i].level < ANDROID_LOG_DEBUG)
|
|
&& (levels[j].level == -2))) {
|
|
if (android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_FALSE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_FALSE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
} else {
|
|
if (!android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_TRUE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_TRUE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
}
|
|
usleep(20000);
|
|
property_set(key + base_offset, "");
|
|
|
|
strcpy(key, log_namespace);
|
|
key[sizeof(log_namespace) - 2] = '\0';
|
|
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
|
|
i, j, key, buf);
|
|
property_set(key, buf);
|
|
android_log_is_loggable = __android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG);
|
|
if ((levels[i].level < levels[j].level)
|
|
|| (levels[j].level == -1)
|
|
|| ((levels[i].level < ANDROID_LOG_DEBUG)
|
|
&& (levels[j].level == -2))) {
|
|
if (android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_FALSE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_FALSE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
} else {
|
|
if (!android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_TRUE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_TRUE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
}
|
|
usleep(20000);
|
|
property_set(key, "");
|
|
|
|
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
|
|
i, j, key + base_offset, buf);
|
|
property_set(key + base_offset, buf);
|
|
android_log_is_loggable = __android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG);
|
|
if ((levels[i].level < levels[j].level)
|
|
|| (levels[j].level == -1)
|
|
|| ((levels[i].level < ANDROID_LOG_DEBUG)
|
|
&& (levels[j].level == -2))) {
|
|
if (android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_FALSE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_FALSE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
} else {
|
|
if (!android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_TRUE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_TRUE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
}
|
|
usleep(20000);
|
|
property_set(key + base_offset, "");
|
|
}
|
|
}
|
|
|
|
// All combinations of level and tag properties, but with global set to INFO
|
|
strcpy(key, log_namespace);
|
|
key[sizeof(log_namespace) - 2] = '\0';
|
|
usleep(20000);
|
|
property_set(key, "I");
|
|
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
|
|
for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
|
|
if (levels[i].level == -2) {
|
|
continue;
|
|
}
|
|
for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
|
|
char buf[2];
|
|
buf[0] = levels[j].type;
|
|
buf[1] = '\0';
|
|
|
|
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
|
|
i, j, key, buf);
|
|
usleep(20000);
|
|
property_set(key, buf);
|
|
bool android_log_is_loggable = __android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG);
|
|
if ((levels[i].level < levels[j].level)
|
|
|| (levels[j].level == -1)
|
|
|| ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
|
|
&& (levels[j].level == -2))) {
|
|
if (android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_FALSE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_FALSE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
} else {
|
|
if (!android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_TRUE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_TRUE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
}
|
|
usleep(20000);
|
|
property_set(key, "");
|
|
|
|
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
|
|
i, j, key + base_offset, buf);
|
|
property_set(key + base_offset, buf);
|
|
android_log_is_loggable = __android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG);
|
|
if ((levels[i].level < levels[j].level)
|
|
|| (levels[j].level == -1)
|
|
|| ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
|
|
&& (levels[j].level == -2))) {
|
|
if (android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_FALSE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_FALSE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
} else {
|
|
if (!android_log_is_loggable) {
|
|
fprintf(stderr, "\n");
|
|
}
|
|
EXPECT_TRUE(android_log_is_loggable);
|
|
for(size_t k = 10; k; --k) {
|
|
EXPECT_TRUE(__android_log_is_loggable(
|
|
levels[i].level, tag, ANDROID_LOG_DEBUG));
|
|
}
|
|
}
|
|
usleep(20000);
|
|
property_set(key + base_offset, "");
|
|
}
|
|
}
|
|
|
|
// reset parms
|
|
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
|
|
usleep(20000);
|
|
property_set(key, hold[0]);
|
|
property_set(key + base_offset, hold[1]);
|
|
strcpy(key, log_namespace);
|
|
key[sizeof(log_namespace) - 2] = '\0';
|
|
property_set(key, hold[2]);
|
|
property_set(key + base_offset, hold[3]);
|
|
}
|
|
|
|
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
|
|
const int TAG = 123456781;
|
|
const char SUBTAG[] = "test-subtag";
|
|
const int UID = -1;
|
|
const int DATA_LEN = 200;
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
ASSERT_LT(0, android_errorWriteWithInfoLog(
|
|
TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
|
|
|
|
sleep(2);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
// Tag
|
|
int tag = get4LE(eventData);
|
|
eventData += 4;
|
|
|
|
if (tag != TAG) {
|
|
continue;
|
|
}
|
|
|
|
// List type
|
|
ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
|
|
eventData++;
|
|
|
|
// Number of elements in list
|
|
ASSERT_EQ(3, eventData[0]);
|
|
eventData++;
|
|
|
|
// Element #1: string type for subtag
|
|
ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
|
|
eventData++;
|
|
|
|
ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
|
|
eventData +=4;
|
|
|
|
if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
|
|
continue;
|
|
}
|
|
eventData += strlen(SUBTAG);
|
|
|
|
// Element #2: int type for uid
|
|
ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
|
|
eventData++;
|
|
|
|
ASSERT_EQ(UID, get4LE(eventData));
|
|
eventData += 4;
|
|
|
|
// Element #3: string type for data
|
|
ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
|
|
eventData++;
|
|
|
|
ASSERT_EQ(DATA_LEN, get4LE(eventData));
|
|
eventData += 4;
|
|
|
|
if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
|
|
continue;
|
|
}
|
|
|
|
++count;
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
|
|
const int TAG = 123456782;
|
|
const char SUBTAG[] = "test-subtag";
|
|
const int UID = -1;
|
|
const int DATA_LEN = sizeof(max_payload_buf);
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
ASSERT_LT(0, android_errorWriteWithInfoLog(
|
|
TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
|
|
|
|
sleep(2);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
char *original = eventData;
|
|
|
|
// Tag
|
|
int tag = get4LE(eventData);
|
|
eventData += 4;
|
|
|
|
if (tag != TAG) {
|
|
continue;
|
|
}
|
|
|
|
// List type
|
|
ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
|
|
eventData++;
|
|
|
|
// Number of elements in list
|
|
ASSERT_EQ(3, eventData[0]);
|
|
eventData++;
|
|
|
|
// Element #1: string type for subtag
|
|
ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
|
|
eventData++;
|
|
|
|
ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
|
|
eventData +=4;
|
|
|
|
if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
|
|
continue;
|
|
}
|
|
eventData += strlen(SUBTAG);
|
|
|
|
// Element #2: int type for uid
|
|
ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
|
|
eventData++;
|
|
|
|
ASSERT_EQ(UID, get4LE(eventData));
|
|
eventData += 4;
|
|
|
|
// Element #3: string type for data
|
|
ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
|
|
eventData++;
|
|
|
|
size_t dataLen = get4LE(eventData);
|
|
eventData += 4;
|
|
|
|
if (memcmp(max_payload_buf, eventData, dataLen)) {
|
|
continue;
|
|
}
|
|
eventData += dataLen;
|
|
|
|
// 4 bytes for the tag, and max_payload_buf should be truncated.
|
|
ASSERT_LE(4 + 512, eventData - original); // worst expectations
|
|
ASSERT_GT(4 + DATA_LEN, eventData - original); // must be truncated
|
|
|
|
++count;
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
|
|
const int TAG = 123456783;
|
|
const char SUBTAG[] = "test-subtag";
|
|
const int UID = -1;
|
|
const int DATA_LEN = 200;
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
ASSERT_GT(0, android_errorWriteWithInfoLog(
|
|
TAG, SUBTAG, UID, NULL, DATA_LEN));
|
|
|
|
sleep(2);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
// Tag
|
|
int tag = get4LE(eventData);
|
|
eventData += 4;
|
|
|
|
if (tag == TAG) {
|
|
// This tag should not have been written because the data was null
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(0, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
|
|
const int TAG = 123456784;
|
|
const char SUBTAG[] = "abcdefghijklmnopqrstuvwxyz now i know my abc";
|
|
const int UID = -1;
|
|
const int DATA_LEN = 200;
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
ASSERT_LT(0, android_errorWriteWithInfoLog(
|
|
TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
|
|
|
|
sleep(2);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
// Tag
|
|
int tag = get4LE(eventData);
|
|
eventData += 4;
|
|
|
|
if (tag != TAG) {
|
|
continue;
|
|
}
|
|
|
|
// List type
|
|
ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
|
|
eventData++;
|
|
|
|
// Number of elements in list
|
|
ASSERT_EQ(3, eventData[0]);
|
|
eventData++;
|
|
|
|
// Element #1: string type for subtag
|
|
ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
|
|
eventData++;
|
|
|
|
// The subtag is longer than 32 and should be truncated to that.
|
|
ASSERT_EQ(32, get4LE(eventData));
|
|
eventData +=4;
|
|
|
|
if (memcmp(SUBTAG, eventData, 32)) {
|
|
continue;
|
|
}
|
|
eventData += 32;
|
|
|
|
// Element #2: int type for uid
|
|
ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
|
|
eventData++;
|
|
|
|
ASSERT_EQ(UID, get4LE(eventData));
|
|
eventData += 4;
|
|
|
|
// Element #3: string type for data
|
|
ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
|
|
eventData++;
|
|
|
|
ASSERT_EQ(DATA_LEN, get4LE(eventData));
|
|
eventData += 4;
|
|
|
|
if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
|
|
continue;
|
|
}
|
|
|
|
++count;
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, __android_log_bswrite_and_print___max) {
|
|
bswrite_test(max_payload_buf);
|
|
}
|
|
|
|
TEST(liblog, __android_log_buf_write_and_print__max) {
|
|
buf_write_test(max_payload_buf);
|
|
}
|
|
|
|
TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
|
|
const int TAG = 123456785;
|
|
const char SUBTAG[] = "test-subtag";
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
ASSERT_LT(0, android_errorWriteLog(TAG, SUBTAG));
|
|
|
|
sleep(2);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
// Tag
|
|
int tag = get4LE(eventData);
|
|
eventData += 4;
|
|
|
|
if (tag != TAG) {
|
|
continue;
|
|
}
|
|
|
|
// List type
|
|
ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
|
|
eventData++;
|
|
|
|
// Number of elements in list
|
|
ASSERT_EQ(3, eventData[0]);
|
|
eventData++;
|
|
|
|
// Element #1: string type for subtag
|
|
ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
|
|
eventData++;
|
|
|
|
ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
|
|
eventData +=4;
|
|
|
|
if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
|
|
continue;
|
|
}
|
|
++count;
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
|
|
const int TAG = 123456786;
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
ASSERT_GT(0, android_errorWriteLog(TAG, NULL));
|
|
|
|
sleep(2);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
// Tag
|
|
int tag = get4LE(eventData);
|
|
eventData += 4;
|
|
|
|
if (tag == TAG) {
|
|
// This tag should not have been written because the data was null
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(0, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
static int is_real_element(int type) {
|
|
return ((type == EVENT_TYPE_INT) ||
|
|
(type == EVENT_TYPE_LONG) ||
|
|
(type == EVENT_TYPE_STRING) ||
|
|
(type == EVENT_TYPE_FLOAT));
|
|
}
|
|
|
|
int android_log_buffer_to_string(const char *msg, size_t len,
|
|
char *strOut, size_t strOutLen) {
|
|
android_log_context context = create_android_log_parser(msg, len);
|
|
android_log_list_element elem;
|
|
bool overflow = false;
|
|
/* Reserve 1 byte for null terminator. */
|
|
size_t origStrOutLen = strOutLen--;
|
|
|
|
if (!context) {
|
|
return -EBADF;
|
|
}
|
|
|
|
memset(&elem, 0, sizeof(elem));
|
|
|
|
size_t outCount;
|
|
|
|
do {
|
|
elem = android_log_read_next(context);
|
|
switch ((int)elem.type) {
|
|
case EVENT_TYPE_LIST:
|
|
if (strOutLen == 0) {
|
|
overflow = true;
|
|
} else {
|
|
*strOut++ = '[';
|
|
strOutLen--;
|
|
}
|
|
break;
|
|
|
|
case EVENT_TYPE_LIST_STOP:
|
|
if (strOutLen == 0) {
|
|
overflow = true;
|
|
} else {
|
|
*strOut++ = ']';
|
|
strOutLen--;
|
|
}
|
|
break;
|
|
|
|
case EVENT_TYPE_INT:
|
|
/*
|
|
* snprintf also requires room for the null terminator, which
|
|
* we don't care about but we have allocated enough room for
|
|
* that
|
|
*/
|
|
outCount = snprintf(strOut, strOutLen + 1,
|
|
"%" PRId32, elem.data.int32);
|
|
if (outCount <= strOutLen) {
|
|
strOut += outCount;
|
|
strOutLen -= outCount;
|
|
} else {
|
|
overflow = true;
|
|
}
|
|
break;
|
|
|
|
case EVENT_TYPE_LONG:
|
|
/*
|
|
* snprintf also requires room for the null terminator, which
|
|
* we don't care about but we have allocated enough room for
|
|
* that
|
|
*/
|
|
outCount = snprintf(strOut, strOutLen + 1,
|
|
"%" PRId64, elem.data.int64);
|
|
if (outCount <= strOutLen) {
|
|
strOut += outCount;
|
|
strOutLen -= outCount;
|
|
} else {
|
|
overflow = true;
|
|
}
|
|
break;
|
|
|
|
case EVENT_TYPE_FLOAT:
|
|
/*
|
|
* snprintf also requires room for the null terminator, which
|
|
* we don't care about but we have allocated enough room for
|
|
* that
|
|
*/
|
|
outCount = snprintf(strOut, strOutLen + 1, "%f", elem.data.float32);
|
|
if (outCount <= strOutLen) {
|
|
strOut += outCount;
|
|
strOutLen -= outCount;
|
|
} else {
|
|
overflow = true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
elem.complete = true;
|
|
break;
|
|
|
|
case EVENT_TYPE_UNKNOWN:
|
|
#if 0 // Ideal purity in the test, we want to complain about UNKNOWN showing up
|
|
if (elem.complete) {
|
|
break;
|
|
}
|
|
#endif
|
|
elem.data.string = const_cast<char *>("<unknown>");
|
|
elem.len = strlen(elem.data.string);
|
|
/* FALLTHRU */
|
|
case EVENT_TYPE_STRING:
|
|
if (elem.len <= strOutLen) {
|
|
memcpy(strOut, elem.data.string, elem.len);
|
|
strOut += elem.len;
|
|
strOutLen -= elem.len;
|
|
} else if (strOutLen > 0) {
|
|
/* copy what we can */
|
|
memcpy(strOut, elem.data.string, strOutLen);
|
|
strOut += strOutLen;
|
|
strOutLen = 0;
|
|
overflow = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (elem.complete) {
|
|
break;
|
|
}
|
|
/* Determine whether to put a comma or not. */
|
|
if (!overflow && (is_real_element(elem.type) ||
|
|
(elem.type == EVENT_TYPE_LIST_STOP))) {
|
|
android_log_list_element next = android_log_peek_next(context);
|
|
if (!next.complete && (is_real_element(next.type) ||
|
|
(next.type == EVENT_TYPE_LIST))) {
|
|
if (strOutLen == 0) {
|
|
overflow = true;
|
|
} else {
|
|
*strOut++ = ',';
|
|
strOutLen--;
|
|
}
|
|
}
|
|
}
|
|
} while ((elem.type != EVENT_TYPE_UNKNOWN) && !overflow && !elem.complete);
|
|
|
|
android_log_destroy(&context);
|
|
|
|
if (overflow) {
|
|
if (strOutLen < origStrOutLen) {
|
|
/* leave an indicator */
|
|
*(strOut-1) = '!';
|
|
} else {
|
|
/* nothing was written at all */
|
|
*strOut++ = '!';
|
|
}
|
|
}
|
|
*strOut++ = '\0';
|
|
|
|
if ((elem.type == EVENT_TYPE_UNKNOWN) && !elem.complete) {
|
|
fprintf(stderr, "Binary log entry conversion failed\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const char *event_test_int32(uint32_t tag, size_t &expected_len) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
|
if (!ctx) {
|
|
return NULL;
|
|
}
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
|
|
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
|
|
expected_len = sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t);
|
|
|
|
return "1076895760";
|
|
}
|
|
|
|
static const char *event_test_int64(uint32_t tag, size_t &expected_len) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
|
if (!ctx) {
|
|
return NULL;
|
|
}
|
|
EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
|
|
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
|
|
expected_len = sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint64_t);
|
|
|
|
return "-9191740941672636400";
|
|
}
|
|
|
|
static const char *event_test_list_int64(uint32_t tag, size_t &expected_len) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
|
if (!ctx) {
|
|
return NULL;
|
|
}
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
|
|
expected_len = sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint8_t) +
|
|
sizeof(uint8_t) + sizeof(uint64_t);
|
|
|
|
return "[-9191740941672636400]";
|
|
}
|
|
|
|
static const char *event_test_simple_automagic_list(uint32_t tag, size_t &expected_len) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
|
if (!ctx) {
|
|
return NULL;
|
|
}
|
|
// The convenience API where we allow a simple list to be
|
|
// created without explicit begin or end calls.
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
|
|
EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
|
|
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
|
|
expected_len = sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint8_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint64_t);
|
|
|
|
return "[1076895760,-9191740941672636400]";
|
|
}
|
|
|
|
static const char *event_test_list_empty(uint32_t tag, size_t &expected_len) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
|
if (!ctx) {
|
|
return NULL;
|
|
}
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
|
|
expected_len = sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint8_t);
|
|
|
|
return "[]";
|
|
}
|
|
|
|
static const char *event_test_complex_nested_list(uint32_t tag, size_t &expected_len) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
|
if (!ctx) {
|
|
return NULL;
|
|
}
|
|
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 0x01020304));
|
|
EXPECT_LE(0, android_log_write_int64(ctx, 0x0102030405060708));
|
|
EXPECT_LE(0, android_log_write_string8(ctx, "Hello World"));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 1));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 2));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 3));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 4));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
|
|
EXPECT_LE(0, android_log_write_float32(ctx, 1.0102030405060708));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
|
|
|
|
//
|
|
// This one checks for the automagic list creation because a list
|
|
// begin and end was missing for it! This is actually an <oops> corner
|
|
// case, and not the behavior we morally support. The automagic API is to
|
|
// allow for a simple case of a series of objects in a single list. e.g.
|
|
// int32,int32,int32,string -> [int32,int32,int32,string]
|
|
//
|
|
EXPECT_LE(0, android_log_write_string8(ctx, "dlroW olleH"));
|
|
|
|
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
|
|
expected_len = sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint8_t) +
|
|
sizeof(uint8_t) + sizeof(uint8_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint64_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) +
|
|
sizeof("Hello World") - 1 +
|
|
sizeof(uint8_t) + sizeof(uint8_t) +
|
|
4 * (sizeof(uint8_t) + sizeof(uint32_t)) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) +
|
|
sizeof("dlroW olleH") - 1;
|
|
|
|
return "[[16909060,72623859790382856,Hello World,[1,2,3,4],1.010203],dlroW olleH]";
|
|
}
|
|
|
|
static const char *event_test_7_level_prefix(uint32_t tag, size_t &expected_len) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
|
if (!ctx) {
|
|
return NULL;
|
|
}
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 1));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 2));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 3));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 4));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 5));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 6));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 7));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
|
|
expected_len = sizeof(uint32_t) + 7 *
|
|
(sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
|
|
|
|
return "[[[[[[[1],2],3],4],5],6],7]";
|
|
}
|
|
|
|
static const char *event_test_7_level_suffix(uint32_t tag, size_t &expected_len) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
|
if (!ctx) {
|
|
return NULL;
|
|
}
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 1));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 2));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 3));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 4));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 5));
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, 6));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list_end(ctx));
|
|
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
|
|
expected_len = sizeof(uint32_t) + 6 *
|
|
(sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
|
|
|
|
return "[1,[2,[3,[4,[5,[6]]]]]]";
|
|
}
|
|
|
|
static const char *event_test_android_log_error_write(uint32_t tag, size_t &expected_len) {
|
|
EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, "dlroW olleH", 11));
|
|
|
|
expected_len = sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint8_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") - 1 +
|
|
sizeof(uint8_t) + sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) + sizeof("dlroW olleH") - 1;
|
|
|
|
return "[Hello World,42,dlroW olleH]";
|
|
}
|
|
|
|
static const char *event_test_android_log_error_write_null(uint32_t tag, size_t &expected_len) {
|
|
EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, NULL, 0));
|
|
|
|
expected_len = sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint8_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") - 1 +
|
|
sizeof(uint8_t) + sizeof(uint32_t) +
|
|
sizeof(uint8_t) + sizeof(uint32_t) + sizeof("") - 1;
|
|
|
|
return "[Hello World,42,]";
|
|
}
|
|
|
|
// make sure all user buffers are flushed
|
|
static void print_barrier() {
|
|
std::cout.flush();
|
|
fflush(stdout);
|
|
std::cerr.flush();
|
|
fflush(stderr); // everything else is paranoia ...
|
|
}
|
|
|
|
static void create_android_logger(const char *(*fn)(uint32_t tag, size_t &expected_len)) {
|
|
struct logger_list *logger_list;
|
|
|
|
pid_t pid = getpid();
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
|
|
|
log_time ts(android_log_clockid());
|
|
|
|
size_t expected_len;
|
|
const char *expected_string = (*fn)(1005, expected_len);
|
|
|
|
if (!expected_string) {
|
|
android_logger_list_close(logger_list);
|
|
return;
|
|
}
|
|
|
|
usleep(1000000);
|
|
|
|
int count = 0;
|
|
|
|
for (;;) {
|
|
log_msg log_msg;
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
|
break;
|
|
}
|
|
|
|
ASSERT_EQ(log_msg.entry.pid, pid);
|
|
|
|
if ((log_msg.entry.sec < (ts.tv_sec - 1))
|
|
|| ((ts.tv_sec + 1) < log_msg.entry.sec)
|
|
|| ((size_t)log_msg.entry.len != expected_len)
|
|
|| (log_msg.id() != LOG_ID_EVENTS)) {
|
|
continue;
|
|
}
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
++count;
|
|
|
|
AndroidLogFormat *logformat = android_log_format_new();
|
|
EXPECT_TRUE(NULL != logformat);
|
|
AndroidLogEntry entry;
|
|
char msgBuf[1024];
|
|
int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
|
|
&log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
|
|
EXPECT_EQ(0, processBinaryLogBuffer);
|
|
if (processBinaryLogBuffer == 0) {
|
|
print_barrier();
|
|
int printLogLine = android_log_printLogLine(
|
|
logformat, fileno(stderr), &entry);
|
|
print_barrier();
|
|
EXPECT_EQ(20 + (int)strlen(expected_string), printLogLine);
|
|
}
|
|
android_log_format_free(logformat);
|
|
|
|
// test buffer reading API
|
|
snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
|
|
print_barrier();
|
|
fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
|
|
memset(msgBuf, 0, sizeof(msgBuf));
|
|
int buffer_to_string = android_log_buffer_to_string(
|
|
eventData + sizeof(uint32_t),
|
|
log_msg.entry.len - sizeof(uint32_t),
|
|
msgBuf, sizeof(msgBuf));
|
|
fprintf(stderr, "%s\n", msgBuf);
|
|
print_barrier();
|
|
EXPECT_EQ(0, buffer_to_string);
|
|
EXPECT_EQ(strlen(expected_string), strlen(msgBuf));
|
|
EXPECT_EQ(0, strcmp(expected_string, msgBuf));
|
|
}
|
|
|
|
EXPECT_EQ(1, count);
|
|
|
|
android_logger_list_close(logger_list);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_int32) {
|
|
create_android_logger(event_test_int32);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_int64) {
|
|
create_android_logger(event_test_int64);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_list_int64) {
|
|
create_android_logger(event_test_list_int64);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_simple_automagic_list) {
|
|
create_android_logger(event_test_simple_automagic_list);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_list_empty) {
|
|
create_android_logger(event_test_list_empty);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_complex_nested_list) {
|
|
create_android_logger(event_test_complex_nested_list);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_7_level_prefix) {
|
|
create_android_logger(event_test_7_level_prefix);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_7_level_suffix) {
|
|
create_android_logger(event_test_7_level_suffix);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_android_log_error_write) {
|
|
create_android_logger(event_test_android_log_error_write);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_android_log_error_write_null) {
|
|
create_android_logger(event_test_android_log_error_write_null);
|
|
}
|
|
|
|
TEST(liblog, create_android_logger_overflow) {
|
|
android_log_context ctx;
|
|
|
|
EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
|
|
if (ctx) {
|
|
for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
}
|
|
EXPECT_GT(0, android_log_write_list_begin(ctx));
|
|
/* One more for good measure, must be permanently unhappy */
|
|
EXPECT_GT(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_destroy(&ctx));
|
|
EXPECT_TRUE(NULL == ctx);
|
|
}
|
|
|
|
ASSERT_TRUE(NULL != (ctx = create_android_logger(1005)));
|
|
for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
|
|
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
|
EXPECT_LE(0, android_log_write_int32(ctx, i));
|
|
}
|
|
EXPECT_GT(0, android_log_write_list_begin(ctx));
|
|
/* One more for good measure, must be permanently unhappy */
|
|
EXPECT_GT(0, android_log_write_list_begin(ctx));
|
|
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"
|
|
"with liblog.__android_log_msg_file_read test\n",
|
|
__pmsg_file);
|
|
}
|
|
|
|
ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
|
|
const char *buf, size_t len, void *arg) {
|
|
EXPECT_TRUE(NULL == arg);
|
|
EXPECT_EQ(LOG_ID_CRASH, logId);
|
|
EXPECT_EQ(ANDROID_LOG_VERBOSE, prio);
|
|
EXPECT_FALSE(NULL == strstr(__pmsg_file, filename));
|
|
EXPECT_EQ(len, sizeof(max_payload_buf));
|
|
EXPECT_EQ(0, strcmp(max_payload_buf, buf));
|
|
|
|
++signaled;
|
|
if ((len != sizeof(max_payload_buf)) ||
|
|
strcmp(max_payload_buf, buf)) {
|
|
fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
|
|
}
|
|
return !arg ||
|
|
(LOG_ID_CRASH != logId) ||
|
|
(ANDROID_LOG_VERBOSE != prio) ||
|
|
!strstr(__pmsg_file, filename) ||
|
|
(len != sizeof(max_payload_buf)) ||
|
|
!!strcmp(max_payload_buf, buf) ? -ENOEXEC : 1;
|
|
}
|
|
|
|
TEST(liblog, __android_log_pmsg_file_read) {
|
|
signaled = 0;
|
|
|
|
ssize_t ret = __android_log_pmsg_file_read(
|
|
LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
|
|
__pmsg_file, __pmsg_fn, NULL);
|
|
|
|
if (ret == -ENOENT) {
|
|
fprintf(stderr,
|
|
"No pre-boot results of liblog.__android_log_mesg_file_write to "
|
|
"compare with,\n"
|
|
"false positive test result.\n");
|
|
return;
|
|
}
|
|
|
|
EXPECT_LT(0, ret);
|
|
EXPECT_EQ(1U, signaled);
|
|
}
|