2014-02-28 21:44:12 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 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>
|
2016-01-21 18:59:25 +00:00
|
|
|
#include <inttypes.h>
|
2014-04-18 21:49:28 +00:00
|
|
|
#include <poll.h>
|
2014-02-28 21:44:12 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2017-01-03 22:00:19 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2016-01-21 18:59:25 +00:00
|
|
|
#include <string>
|
|
|
|
|
2016-11-03 17:29:23 +00:00
|
|
|
#include <android-base/macros.h>
|
2016-01-21 18:59:25 +00:00
|
|
|
#include <android-base/stringprintf.h>
|
|
|
|
#include <cutils/sockets.h>
|
2016-09-28 22:54:45 +00:00
|
|
|
#include <gtest/gtest.h>
|
2016-09-30 20:30:33 +00:00
|
|
|
#include <log/log.h>
|
2017-01-03 22:00:19 +00:00
|
|
|
#include <private/android_filesystem_config.h>
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
#include <selinux/selinux.h>
|
|
|
|
#endif
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2017-01-03 22:00:19 +00:00
|
|
|
#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
|
2016-02-23 16:55:43 +00:00
|
|
|
#include "../LogReader.h" // pickup LOGD_SNDTIMEO
|
|
|
|
|
2016-09-12 21:51:54 +00:00
|
|
|
static void send_to_control(char* buf, size_t len)
|
2014-02-28 21:44:12 +00:00
|
|
|
{
|
|
|
|
int sock = socket_local_client("logd",
|
|
|
|
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
|
|
SOCK_STREAM);
|
|
|
|
if (sock >= 0) {
|
|
|
|
if (write(sock, buf, strlen(buf) + 1) > 0) {
|
2014-04-18 21:49:28 +00:00
|
|
|
ssize_t ret;
|
|
|
|
while ((ret = read(sock, buf, len)) > 0) {
|
liblog: add android_lookupEventTagNum
android_lookupEventTagNum added. Adds support for creating a new
log tag at runtime, registered to the logd service.
Tested on Hikey, all services stopped, shell only access, CPUs not
locked (there is enough repeatability on this platform).
$ /data/nativetest64/liblog-benchmarks/liblog-benchmarks BM_lookupEventTagNum
iterations ns/op
Precharge: start
Precharge: stop 231
NB: only Tag matching, linear lookup (as reference, before unordered_map)
BM_lookupEventTagNum 1000000 1017
NB: unordered_map with full Tag & Format lookup, but with Tag hashing
BM_lookupEventTagNum 2000000 683
NB: with full Tag & Format hash and lookup for matching
BM_lookupEventTagNum 2000000 814
NB: only Tag matching (Hail Mary path)
BM_lookupEventTagNum 5000000 471
Because the database can now be dynamic, we added reader/writer locks
which adds a 65ns (uncontended) premium on lookups, and switch to
check for an allocation adds 25ns (either open code, or using
string_view, no difference) which means our overall speed takes 90%
as long as the requests did before we switched to unordered_map.
Faster than before where we originally utilized binary lookup on
static content, but not by much. Dynamic updates that are not cached
locally take the following times to acquire long path to logd to
generate.
BM_lookupEventTag 20000000 139
BM_lookupEventTag_NOT 20000000 87
BM_lookupEventFormat 20000000 139
BM_lookupEventTagNum_logd_new 5000 335936
BM_lookupEventTagNum_logd_existing 10000 249226
The long path pickups are mitigated by the built-in caching, and
the public mapping in /dev/event-log-tags.
SideEffects: Event tags and signal handlers do not mix
Test: liblog benchmarks
Bug: 31456426
Change-Id: I69e6489d899cf35cdccffcee0d8d7cad469ada0a
2016-09-21 16:24:13 +00:00
|
|
|
if (((size_t)ret == len) || (len < PAGE_SIZE)) {
|
2014-04-18 21:49:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
len -= ret;
|
|
|
|
buf += ret;
|
|
|
|
|
|
|
|
struct pollfd p = {
|
|
|
|
.fd = sock,
|
|
|
|
.events = POLLIN,
|
|
|
|
.revents = 0
|
|
|
|
};
|
|
|
|
|
|
|
|
ret = poll(&p, 1, 20);
|
|
|
|
if ((ret <= 0) || !(p.revents & POLLIN)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
|
|
|
close(sock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 21:51:54 +00:00
|
|
|
/*
|
|
|
|
* returns statistics
|
|
|
|
*/
|
|
|
|
static void my_android_logger_get_statistics(char *buf, size_t len)
|
|
|
|
{
|
|
|
|
snprintf(buf, len, "getStatistics 0 1 2 3 4");
|
|
|
|
send_to_control(buf, len);
|
|
|
|
}
|
|
|
|
|
2014-02-28 21:44:12 +00:00
|
|
|
static void alloc_statistics(char **buffer, size_t *length)
|
|
|
|
{
|
|
|
|
size_t len = 8192;
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
for(int retry = 32; (retry >= 0); delete [] buf, --retry) {
|
|
|
|
buf = new char [len];
|
|
|
|
my_android_logger_get_statistics(buf, len);
|
|
|
|
|
|
|
|
buf[len-1] = '\0';
|
|
|
|
size_t ret = atol(buf) + 1;
|
|
|
|
if (ret < 4) {
|
|
|
|
delete [] buf;
|
|
|
|
buf = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bool check = ret <= len;
|
|
|
|
len = ret;
|
|
|
|
if (check) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
len += len / 8; // allow for some slop
|
|
|
|
}
|
|
|
|
*buffer = buf;
|
|
|
|
*length = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *find_benchmark_spam(char *cp)
|
|
|
|
{
|
|
|
|
// liblog_benchmarks has been run designed to SPAM. The signature of
|
2015-05-26 18:00:45 +00:00
|
|
|
// a noisiest UID statistics is:
|
2014-02-28 21:44:12 +00:00
|
|
|
//
|
2015-05-26 18:00:45 +00:00
|
|
|
// Chattiest UIDs in main log buffer: Size Pruned
|
|
|
|
// UID PACKAGE BYTES LINES
|
|
|
|
// 0 root 54164 147569
|
2014-02-28 21:44:12 +00:00
|
|
|
//
|
2015-05-26 18:00:45 +00:00
|
|
|
char *benchmark = NULL;
|
2014-02-28 21:44:12 +00:00
|
|
|
do {
|
2015-05-26 18:00:45 +00:00
|
|
|
static const char signature[] = "\n0 root ";
|
|
|
|
|
|
|
|
benchmark = strstr(cp, signature);
|
2014-02-28 21:44:12 +00:00
|
|
|
if (!benchmark) {
|
2015-05-26 18:00:45 +00:00
|
|
|
break;
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
2015-05-26 18:00:45 +00:00
|
|
|
cp = benchmark + sizeof(signature);
|
|
|
|
while (isspace(*cp)) {
|
|
|
|
++cp;
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
2015-05-26 18:00:45 +00:00
|
|
|
benchmark = cp;
|
2015-12-01 19:13:20 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
char *end = strstr(benchmark, "\n");
|
|
|
|
if (end == NULL) {
|
|
|
|
end = benchmark + strlen(benchmark);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "parse for spam counter in \"%.*s\"\n",
|
|
|
|
(int)(end - benchmark), benchmark);
|
|
|
|
#endif
|
|
|
|
// content
|
2015-05-26 18:00:45 +00:00
|
|
|
while (isdigit(*cp)) {
|
|
|
|
++cp;
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
2015-05-26 18:00:45 +00:00
|
|
|
while (isspace(*cp)) {
|
2014-02-28 21:44:12 +00:00
|
|
|
++cp;
|
|
|
|
}
|
2015-12-01 19:13:20 +00:00
|
|
|
// optional +/- field?
|
|
|
|
if ((*cp == '-') || (*cp == '+')) {
|
|
|
|
while (isdigit(*++cp) ||
|
|
|
|
(*cp == '.') || (*cp == '%') || (*cp == 'X')) {
|
|
|
|
;
|
|
|
|
}
|
|
|
|
while (isspace(*cp)) {
|
|
|
|
++cp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// number of entries pruned
|
2015-05-26 18:00:45 +00:00
|
|
|
unsigned long value = 0;
|
|
|
|
while (isdigit(*cp)) {
|
|
|
|
value = value * 10ULL + *cp - '0';
|
|
|
|
++cp;
|
|
|
|
}
|
2015-12-01 19:13:20 +00:00
|
|
|
if (value > 10UL) {
|
2015-05-26 18:00:45 +00:00
|
|
|
break;
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
2015-05-26 18:00:45 +00:00
|
|
|
benchmark = NULL;
|
|
|
|
} while (*cp);
|
|
|
|
return benchmark;
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, statistics) {
|
|
|
|
size_t len;
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
alloc_statistics(&buf, &len);
|
|
|
|
|
|
|
|
ASSERT_TRUE(NULL != buf);
|
|
|
|
|
|
|
|
// remove trailing FF
|
|
|
|
char *cp = buf + len - 1;
|
|
|
|
*cp = '\0';
|
|
|
|
bool truncated = *--cp != '\f';
|
|
|
|
if (!truncated) {
|
|
|
|
*cp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
// squash out the byte count
|
|
|
|
cp = buf;
|
|
|
|
if (!truncated) {
|
|
|
|
while (isdigit(*cp) || (*cp == '\n')) {
|
|
|
|
++cp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%s", cp);
|
|
|
|
|
|
|
|
EXPECT_LT((size_t)64, strlen(cp));
|
|
|
|
|
|
|
|
EXPECT_EQ(0, truncated);
|
|
|
|
|
2015-05-26 18:00:45 +00:00
|
|
|
char *main_logs = strstr(cp, "\nChattiest UIDs in main ");
|
2014-02-28 21:44:12 +00:00
|
|
|
EXPECT_TRUE(NULL != main_logs);
|
|
|
|
|
2015-05-26 18:00:45 +00:00
|
|
|
char *radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
|
2017-01-09 20:43:44 +00:00
|
|
|
if (!radio_logs) GTEST_LOG_(INFO) << "Value of: NULL != radio_logs\n"
|
|
|
|
"Actual: false\n"
|
|
|
|
"Expected: false\n";
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2015-05-26 18:00:45 +00:00
|
|
|
char *system_logs = strstr(cp, "\nChattiest UIDs in system ");
|
2014-02-28 21:44:12 +00:00
|
|
|
EXPECT_TRUE(NULL != system_logs);
|
|
|
|
|
2015-05-26 18:00:45 +00:00
|
|
|
char *events_logs = strstr(cp, "\nChattiest UIDs in events ");
|
2014-02-28 21:44:12 +00:00
|
|
|
EXPECT_TRUE(NULL != events_logs);
|
|
|
|
|
|
|
|
delete [] buf;
|
|
|
|
}
|
|
|
|
|
2015-12-07 20:27:06 +00:00
|
|
|
static void caught_signal(int /* signum */) { }
|
2014-02-28 21:44:12 +00:00
|
|
|
|
|
|
|
static void dump_log_msg(const char *prefix,
|
|
|
|
log_msg *msg, unsigned int version, int lid) {
|
2016-01-21 18:59:25 +00:00
|
|
|
std::cout << std::flush;
|
|
|
|
std::cerr << std::flush;
|
|
|
|
fflush(stdout);
|
|
|
|
fflush(stderr);
|
2014-02-28 21:44:12 +00:00
|
|
|
switch(msg->entry.hdr_size) {
|
|
|
|
case 0:
|
|
|
|
version = 1;
|
|
|
|
break;
|
|
|
|
|
2016-08-18 21:59:41 +00:00
|
|
|
case sizeof(msg->entry_v2): /* PLUS case sizeof(msg->entry_v3): */
|
2014-02-28 21:44:12 +00:00
|
|
|
if (version == 0) {
|
2016-08-18 21:59:41 +00:00
|
|
|
version = (msg->entry_v3.lid < LOG_ID_MAX) ? 3 : 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sizeof(msg->entry_v4):
|
|
|
|
if (version == 0) {
|
|
|
|
version = 4;
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%s: v%u[%u] ", prefix, version, msg->len());
|
|
|
|
if (version != 1) {
|
|
|
|
fprintf(stderr, "hdr_size=%u ", msg->entry.hdr_size);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "pid=%u tid=%u %u.%09u ",
|
|
|
|
msg->entry.pid, msg->entry.tid, msg->entry.sec, msg->entry.nsec);
|
|
|
|
switch(version) {
|
|
|
|
case 1:
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
fprintf(stderr, "euid=%u ", msg->entry_v2.euid);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
default:
|
|
|
|
lid = msg->entry.lid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(lid) {
|
|
|
|
case 0:
|
|
|
|
fprintf(stderr, "lid=main ");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
fprintf(stderr, "lid=radio ");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
fprintf(stderr, "lid=events ");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
fprintf(stderr, "lid=system ");
|
|
|
|
break;
|
2015-12-01 16:57:53 +00:00
|
|
|
case 4:
|
|
|
|
fprintf(stderr, "lid=crash ");
|
|
|
|
break;
|
|
|
|
case 5:
|
2016-02-23 16:55:43 +00:00
|
|
|
fprintf(stderr, "lid=security ");
|
|
|
|
break;
|
|
|
|
case 6:
|
2015-12-01 16:57:53 +00:00
|
|
|
fprintf(stderr, "lid=kernel ");
|
|
|
|
break;
|
2014-02-28 21:44:12 +00:00
|
|
|
default:
|
|
|
|
if (lid >= 0) {
|
|
|
|
fprintf(stderr, "lid=%d ", lid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int len = msg->entry.len;
|
|
|
|
fprintf(stderr, "msg[%u]={", len);
|
|
|
|
unsigned char *cp = reinterpret_cast<unsigned char *>(msg->msg());
|
2016-08-18 21:59:41 +00:00
|
|
|
if (!cp) {
|
|
|
|
static const unsigned char garbage[] = "<INVALID>";
|
|
|
|
cp = const_cast<unsigned char *>(garbage);
|
|
|
|
len = strlen(reinterpret_cast<const char *>(garbage));
|
|
|
|
}
|
2014-02-28 21:44:12 +00:00
|
|
|
while(len) {
|
|
|
|
unsigned char *p = cp;
|
|
|
|
while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
if (((p - cp) > 3) && !*p && ((unsigned int)(p - cp) < len)) {
|
|
|
|
fprintf(stderr, "\"");
|
|
|
|
while (*cp) {
|
2014-09-12 23:02:28 +00:00
|
|
|
if (*cp != '\n') {
|
|
|
|
fprintf(stderr, "%c", *cp);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "\\n");
|
|
|
|
}
|
2014-02-28 21:44:12 +00:00
|
|
|
++cp;
|
|
|
|
--len;
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\"");
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%02x", *cp);
|
|
|
|
}
|
|
|
|
++cp;
|
|
|
|
if (--len) {
|
|
|
|
fprintf(stderr, ", ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fprintf(stderr, "}\n");
|
2016-01-21 18:59:25 +00:00
|
|
|
fflush(stderr);
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, both) {
|
|
|
|
log_msg msg;
|
|
|
|
|
|
|
|
// check if we can read any logs from logd
|
|
|
|
bool user_logger_available = false;
|
|
|
|
bool user_logger_content = false;
|
|
|
|
|
|
|
|
int fd = socket_local_client("logdr",
|
|
|
|
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
|
|
SOCK_SEQPACKET);
|
|
|
|
if (fd >= 0) {
|
|
|
|
struct sigaction ignore, old_sigaction;
|
|
|
|
memset(&ignore, 0, sizeof(ignore));
|
|
|
|
ignore.sa_handler = caught_signal;
|
|
|
|
sigemptyset(&ignore.sa_mask);
|
|
|
|
sigaction(SIGALRM, &ignore, &old_sigaction);
|
|
|
|
unsigned int old_alarm = alarm(10);
|
|
|
|
|
|
|
|
static const char ask[] = "dumpAndClose lids=0,1,2,3";
|
|
|
|
user_logger_available = write(fd, ask, sizeof(ask)) == sizeof(ask);
|
|
|
|
|
|
|
|
user_logger_content = recv(fd, msg.buf, sizeof(msg), 0) > 0;
|
|
|
|
|
|
|
|
if (user_logger_content) {
|
|
|
|
dump_log_msg("user", &msg, 3, -1);
|
|
|
|
}
|
|
|
|
|
2014-04-30 16:21:54 +00:00
|
|
|
alarm(old_alarm);
|
2014-02-28 21:44:12 +00:00
|
|
|
sigaction(SIGALRM, &old_sigaction, NULL);
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if we can read any logs from kernel logger
|
|
|
|
bool kernel_logger_available = false;
|
|
|
|
bool kernel_logger_content = false;
|
|
|
|
|
|
|
|
static const char *loggers[] = {
|
|
|
|
"/dev/log/main", "/dev/log_main",
|
|
|
|
"/dev/log/radio", "/dev/log_radio",
|
|
|
|
"/dev/log/events", "/dev/log_events",
|
|
|
|
"/dev/log/system", "/dev/log_system",
|
|
|
|
};
|
|
|
|
|
2016-11-03 17:29:23 +00:00
|
|
|
for (unsigned int i = 0; i < arraysize(loggers); ++i) {
|
2014-02-28 21:44:12 +00:00
|
|
|
fd = open(loggers[i], O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
kernel_logger_available = true;
|
|
|
|
fcntl(fd, F_SETFL, O_RDONLY | O_NONBLOCK);
|
|
|
|
int result = TEMP_FAILURE_RETRY(read(fd, msg.buf, sizeof(msg)));
|
|
|
|
if (result > 0) {
|
|
|
|
kernel_logger_content = true;
|
|
|
|
dump_log_msg("kernel", &msg, 0, i / 2);
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char yes[] = "\xE2\x9C\x93";
|
|
|
|
static const char no[] = "\xE2\x9c\x98";
|
|
|
|
fprintf(stderr,
|
|
|
|
"LOGGER Available Content\n"
|
|
|
|
"user %-13s%s\n"
|
|
|
|
"kernel %-13s%s\n"
|
|
|
|
" status %-11s%s\n",
|
|
|
|
(user_logger_available) ? yes : no,
|
|
|
|
(user_logger_content) ? yes : no,
|
|
|
|
(kernel_logger_available) ? yes : no,
|
|
|
|
(kernel_logger_content) ? yes : no,
|
2014-07-10 20:31:57 +00:00
|
|
|
(user_logger_available && kernel_logger_available) ? "ERROR" : "ok",
|
2014-02-28 21:44:12 +00:00
|
|
|
(user_logger_content && kernel_logger_content) ? "ERROR" : "ok");
|
|
|
|
|
2014-07-10 20:31:57 +00:00
|
|
|
EXPECT_EQ(0, user_logger_available && kernel_logger_available);
|
|
|
|
EXPECT_EQ(0, !user_logger_available && !kernel_logger_available);
|
2014-02-28 21:44:12 +00:00
|
|
|
EXPECT_EQ(0, user_logger_content && kernel_logger_content);
|
|
|
|
EXPECT_EQ(0, !user_logger_content && !kernel_logger_content);
|
|
|
|
}
|
|
|
|
|
|
|
|
// BAD ROBOT
|
|
|
|
// Benchmark threshold are generally considered bad form unless there is
|
|
|
|
// is some human love applied to the continued maintenance and whether the
|
|
|
|
// thresholds are tuned on a per-target basis. Here we check if the values
|
|
|
|
// are more than double what is expected. Doubling will not prevent failure
|
|
|
|
// on busy or low-end systems that could have a tendency to stretch values.
|
|
|
|
//
|
|
|
|
// The primary goal of this test is to simulate a spammy app (benchmark
|
|
|
|
// being the worst) and check to make sure the logger can deal with it
|
|
|
|
// appropriately by checking all the statistics are in an expected range.
|
|
|
|
//
|
|
|
|
TEST(logd, benchmark) {
|
|
|
|
size_t len;
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
alloc_statistics(&buf, &len);
|
|
|
|
bool benchmark_already_run = buf && find_benchmark_spam(buf);
|
|
|
|
delete [] buf;
|
|
|
|
|
|
|
|
if (benchmark_already_run) {
|
|
|
|
fprintf(stderr, "WARNING: spam already present and too much history\n"
|
|
|
|
" false OK for prune by worst UID check\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
// Introduce some extreme spam for the worst UID filter
|
|
|
|
ASSERT_TRUE(NULL != (fp = popen(
|
2016-12-27 21:30:03 +00:00
|
|
|
"/data/nativetest/liblog-benchmarks/liblog-benchmarks"
|
|
|
|
" BM_log_maximum_retry"
|
|
|
|
" BM_log_maximum"
|
|
|
|
" BM_clock_overhead"
|
|
|
|
" BM_log_overhead"
|
|
|
|
" BM_log_latency"
|
|
|
|
" BM_log_delay",
|
2014-02-28 21:44:12 +00:00
|
|
|
"r")));
|
|
|
|
|
|
|
|
char buffer[5120];
|
|
|
|
|
|
|
|
static const char *benchmarks[] = {
|
|
|
|
"BM_log_maximum_retry ",
|
|
|
|
"BM_log_maximum ",
|
|
|
|
"BM_clock_overhead ",
|
|
|
|
"BM_log_overhead ",
|
|
|
|
"BM_log_latency ",
|
|
|
|
"BM_log_delay "
|
|
|
|
};
|
|
|
|
static const unsigned int log_maximum_retry = 0;
|
|
|
|
static const unsigned int log_maximum = 1;
|
|
|
|
static const unsigned int clock_overhead = 2;
|
|
|
|
static const unsigned int log_overhead = 3;
|
|
|
|
static const unsigned int log_latency = 4;
|
|
|
|
static const unsigned int log_delay = 5;
|
|
|
|
|
2016-11-03 17:29:23 +00:00
|
|
|
unsigned long ns[arraysize(benchmarks)];
|
2014-02-28 21:44:12 +00:00
|
|
|
|
|
|
|
memset(ns, 0, sizeof(ns));
|
|
|
|
|
|
|
|
while (fgets(buffer, sizeof(buffer), fp)) {
|
2016-11-03 17:29:23 +00:00
|
|
|
for (unsigned i = 0; i < arraysize(ns); ++i) {
|
2014-06-06 20:38:42 +00:00
|
|
|
char *cp = strstr(buffer, benchmarks[i]);
|
|
|
|
if (!cp) {
|
2014-02-28 21:44:12 +00:00
|
|
|
continue;
|
|
|
|
}
|
2014-06-06 20:38:42 +00:00
|
|
|
sscanf(cp, "%*s %lu %lu", &ns[i], &ns[i]);
|
2014-02-28 21:44:12 +00:00
|
|
|
fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int ret = pclose(fp);
|
|
|
|
|
|
|
|
if (!WIFEXITED(ret) || (WEXITSTATUS(ret) == 127)) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: "
|
|
|
|
"/data/nativetest/liblog-benchmarks/liblog-benchmarks missing\n"
|
|
|
|
" can not perform test\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-26 18:00:45 +00:00
|
|
|
EXPECT_GE(200000UL, ns[log_maximum_retry]); // 104734 user
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2015-05-26 18:00:45 +00:00
|
|
|
EXPECT_GE(90000UL, ns[log_maximum]); // 46913 user
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2014-06-06 20:38:42 +00:00
|
|
|
EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2015-05-26 18:00:45 +00:00
|
|
|
EXPECT_GE(250000UL, ns[log_overhead]); // 126886 user
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2015-12-01 16:57:53 +00:00
|
|
|
EXPECT_GE(10000000UL, ns[log_latency]); // 1453559 user space (background cgroup)
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2014-06-06 20:38:42 +00:00
|
|
|
EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
|
2014-02-28 21:44:12 +00:00
|
|
|
|
2016-11-03 17:29:23 +00:00
|
|
|
for (unsigned i = 0; i < arraysize(ns); ++i) {
|
2014-02-28 21:44:12 +00:00
|
|
|
EXPECT_NE(0UL, ns[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
alloc_statistics(&buf, &len);
|
|
|
|
|
|
|
|
bool collected_statistics = !!buf;
|
|
|
|
EXPECT_EQ(true, collected_statistics);
|
|
|
|
|
|
|
|
ASSERT_TRUE(NULL != buf);
|
2014-04-09 17:02:23 +00:00
|
|
|
|
|
|
|
char *benchmark_statistics_found = find_benchmark_spam(buf);
|
|
|
|
ASSERT_TRUE(benchmark_statistics_found != NULL);
|
|
|
|
|
|
|
|
// Check how effective the SPAM filter is, parse out Now size.
|
2015-05-26 18:00:45 +00:00
|
|
|
// 0 root 54164 147569
|
2014-04-09 17:02:23 +00:00
|
|
|
// ^-- benchmark_statistics_found
|
|
|
|
|
2014-06-06 20:38:42 +00:00
|
|
|
unsigned long nowSpamSize = atol(benchmark_statistics_found);
|
2014-02-28 21:44:12 +00:00
|
|
|
|
|
|
|
delete [] buf;
|
2014-04-09 17:02:23 +00:00
|
|
|
|
2014-06-06 20:38:42 +00:00
|
|
|
ASSERT_NE(0UL, nowSpamSize);
|
2014-04-09 17:02:23 +00:00
|
|
|
|
2014-06-13 17:09:55 +00:00
|
|
|
// Determine if we have the spam filter enabled
|
2014-04-09 17:02:23 +00:00
|
|
|
int sock = socket_local_client("logd",
|
|
|
|
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
|
|
SOCK_STREAM);
|
2014-06-13 17:09:55 +00:00
|
|
|
|
|
|
|
ASSERT_TRUE(sock >= 0);
|
|
|
|
|
|
|
|
static const char getPruneList[] = "getPruneList";
|
|
|
|
if (write(sock, getPruneList, sizeof(getPruneList)) > 0) {
|
|
|
|
char buffer[80];
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
read(sock, buffer, sizeof(buffer));
|
|
|
|
char *cp = strchr(buffer, '\n');
|
|
|
|
if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
|
|
|
|
close(sock);
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: "
|
|
|
|
"Logger has SPAM filtration turned off \"%s\"\n", buffer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int save_errno = errno;
|
|
|
|
close(sock);
|
|
|
|
FAIL() << "Can not send " << getPruneList << " to logger -- " << strerror(save_errno);
|
|
|
|
}
|
|
|
|
|
2014-04-09 17:02:23 +00:00
|
|
|
static const unsigned long expected_absolute_minimum_log_size = 65536UL;
|
|
|
|
unsigned long totalSize = expected_absolute_minimum_log_size;
|
2014-06-13 17:09:55 +00:00
|
|
|
static const char getSize[] = {
|
|
|
|
'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
|
|
|
|
LOG_ID_MAIN + '0', '\0'
|
|
|
|
};
|
|
|
|
if (write(sock, getSize, sizeof(getSize)) > 0) {
|
|
|
|
char buffer[80];
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
read(sock, buffer, sizeof(buffer));
|
|
|
|
totalSize = atol(buffer);
|
|
|
|
if (totalSize < expected_absolute_minimum_log_size) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: "
|
|
|
|
"Logger had unexpected referenced size \"%s\"\n", buffer);
|
|
|
|
totalSize = expected_absolute_minimum_log_size;
|
2014-04-09 17:02:23 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-13 17:09:55 +00:00
|
|
|
close(sock);
|
|
|
|
|
2014-04-09 17:02:23 +00:00
|
|
|
// logd allows excursions to 110% of total size
|
|
|
|
totalSize = (totalSize * 11 ) / 10;
|
|
|
|
|
|
|
|
// 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
|
2014-06-06 20:38:42 +00:00
|
|
|
ASSERT_GT(totalSize, nowSpamSize * 2);
|
2014-02-28 21:44:12 +00:00
|
|
|
}
|
2015-12-01 16:57:53 +00:00
|
|
|
|
2016-01-21 18:59:25 +00:00
|
|
|
// b/26447386 confirm fixed
|
|
|
|
void timeout_negative(const char *command) {
|
2015-12-01 16:57:53 +00:00
|
|
|
log_msg msg_wrap, msg_timeout;
|
|
|
|
bool content_wrap = false, content_timeout = false, written = false;
|
|
|
|
unsigned int alarm_wrap = 0, alarm_timeout = 0;
|
|
|
|
// A few tries to get it right just in case wrap kicks in due to
|
|
|
|
// content providers being active during the test.
|
|
|
|
int i = 3;
|
|
|
|
|
|
|
|
while (--i) {
|
|
|
|
int fd = socket_local_client("logdr",
|
|
|
|
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
|
|
SOCK_SEQPACKET);
|
|
|
|
ASSERT_LT(0, fd);
|
|
|
|
|
2016-01-21 18:59:25 +00:00
|
|
|
std::string ask(command);
|
|
|
|
|
2015-12-01 16:57:53 +00:00
|
|
|
struct sigaction ignore, old_sigaction;
|
|
|
|
memset(&ignore, 0, sizeof(ignore));
|
|
|
|
ignore.sa_handler = caught_signal;
|
|
|
|
sigemptyset(&ignore.sa_mask);
|
|
|
|
sigaction(SIGALRM, &ignore, &old_sigaction);
|
|
|
|
unsigned int old_alarm = alarm(3);
|
|
|
|
|
2016-01-21 18:59:25 +00:00
|
|
|
size_t len = ask.length() + 1;
|
|
|
|
written = write(fd, ask.c_str(), len) == (ssize_t)len;
|
2015-12-01 16:57:53 +00:00
|
|
|
if (!written) {
|
|
|
|
alarm(old_alarm);
|
|
|
|
sigaction(SIGALRM, &old_sigaction, NULL);
|
|
|
|
close(fd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-12-27 21:30:03 +00:00
|
|
|
// alarm triggers at 50% of the --wrap time out
|
2015-12-01 16:57:53 +00:00
|
|
|
content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
|
|
|
|
|
|
|
|
alarm_wrap = alarm(5);
|
|
|
|
|
2016-12-27 21:30:03 +00:00
|
|
|
// alarm triggers at 133% of the --wrap time out
|
2015-12-01 16:57:53 +00:00
|
|
|
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
2016-01-21 18:59:25 +00:00
|
|
|
if (!content_timeout) { // make sure we hit dumpAndClose
|
|
|
|
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
|
|
|
}
|
2015-12-01 16:57:53 +00:00
|
|
|
|
|
|
|
alarm_timeout = alarm((old_alarm <= 0)
|
|
|
|
? old_alarm
|
|
|
|
: (old_alarm > (1 + 3 - alarm_wrap))
|
|
|
|
? old_alarm - 3 + alarm_wrap
|
|
|
|
: 2);
|
|
|
|
sigaction(SIGALRM, &old_sigaction, NULL);
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
2016-01-21 18:59:25 +00:00
|
|
|
if (!content_wrap && !alarm_wrap && content_timeout && alarm_timeout) {
|
2015-12-01 16:57:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content_wrap) {
|
|
|
|
dump_log_msg("wrap", &msg_wrap, 3, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content_timeout) {
|
|
|
|
dump_log_msg("timeout", &msg_timeout, 3, -1);
|
|
|
|
}
|
|
|
|
|
2016-01-21 18:59:25 +00:00
|
|
|
EXPECT_TRUE(written);
|
|
|
|
EXPECT_TRUE(content_wrap);
|
|
|
|
EXPECT_NE(0U, alarm_wrap);
|
|
|
|
EXPECT_TRUE(content_timeout);
|
|
|
|
EXPECT_NE(0U, alarm_timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, timeout_no_start) {
|
|
|
|
timeout_negative("dumpAndClose lids=0,1,2,3,4,5 timeout=6");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, timeout_start_epoch) {
|
|
|
|
timeout_negative("dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=0.000000000");
|
|
|
|
}
|
|
|
|
|
|
|
|
// b/26447386 refined behavior
|
|
|
|
TEST(logd, timeout) {
|
2016-12-27 21:30:03 +00:00
|
|
|
// b/33962045 This test interferes with other log reader tests that
|
|
|
|
// follow because of file descriptor socket persistence in the same
|
|
|
|
// process. So let's fork it to isolate it from giving us pain.
|
|
|
|
|
|
|
|
pid_t pid = fork();
|
|
|
|
|
|
|
|
if (pid) {
|
|
|
|
siginfo_t info = {};
|
|
|
|
ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
|
|
|
|
ASSERT_EQ(0, info.si_status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-21 18:59:25 +00:00
|
|
|
log_msg msg_wrap, msg_timeout;
|
|
|
|
bool content_wrap = false, content_timeout = false, written = false;
|
|
|
|
unsigned int alarm_wrap = 0, alarm_timeout = 0;
|
|
|
|
// A few tries to get it right just in case wrap kicks in due to
|
2016-12-27 21:30:03 +00:00
|
|
|
// content providers being active during the test.
|
2016-01-21 18:59:25 +00:00
|
|
|
int i = 5;
|
|
|
|
log_time now(android_log_clockid());
|
|
|
|
now.tv_sec -= 30; // reach back a moderate period of time
|
|
|
|
|
|
|
|
while (--i) {
|
|
|
|
int fd = socket_local_client("logdr",
|
|
|
|
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
|
|
SOCK_SEQPACKET);
|
2016-12-27 21:30:03 +00:00
|
|
|
EXPECT_LT(0, fd);
|
|
|
|
if (fd < 0) _exit(fd);
|
2016-01-21 18:59:25 +00:00
|
|
|
|
|
|
|
std::string ask = android::base::StringPrintf(
|
|
|
|
"dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%"
|
|
|
|
PRIu32 ".%09" PRIu32,
|
|
|
|
now.tv_sec, now.tv_nsec);
|
|
|
|
|
|
|
|
struct sigaction ignore, old_sigaction;
|
|
|
|
memset(&ignore, 0, sizeof(ignore));
|
|
|
|
ignore.sa_handler = caught_signal;
|
|
|
|
sigemptyset(&ignore.sa_mask);
|
|
|
|
sigaction(SIGALRM, &ignore, &old_sigaction);
|
|
|
|
unsigned int old_alarm = alarm(3);
|
|
|
|
|
|
|
|
size_t len = ask.length() + 1;
|
|
|
|
written = write(fd, ask.c_str(), len) == (ssize_t)len;
|
|
|
|
if (!written) {
|
|
|
|
alarm(old_alarm);
|
|
|
|
sigaction(SIGALRM, &old_sigaction, NULL);
|
|
|
|
close(fd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-12-27 21:30:03 +00:00
|
|
|
// alarm triggers at 50% of the --wrap time out
|
2016-01-21 18:59:25 +00:00
|
|
|
content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
|
|
|
|
|
|
|
|
alarm_wrap = alarm(5);
|
|
|
|
|
2016-12-27 21:30:03 +00:00
|
|
|
// alarm triggers at 133% of the --wrap time out
|
2016-01-21 18:59:25 +00:00
|
|
|
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
|
|
|
if (!content_timeout) { // make sure we hit dumpAndClose
|
|
|
|
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
alarm_timeout = alarm((old_alarm <= 0)
|
|
|
|
? old_alarm
|
|
|
|
: (old_alarm > (1 + 3 - alarm_wrap))
|
|
|
|
? old_alarm - 3 + alarm_wrap
|
|
|
|
: 2);
|
|
|
|
sigaction(SIGALRM, &old_sigaction, NULL);
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (!content_wrap && !alarm_wrap && content_timeout && alarm_timeout) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// modify start time in case content providers are relatively
|
|
|
|
// active _or_ inactive during the test.
|
|
|
|
if (content_timeout) {
|
|
|
|
log_time msg(msg_timeout.entry.sec, msg_timeout.entry.nsec);
|
|
|
|
EXPECT_FALSE(msg < now);
|
2016-12-27 21:30:03 +00:00
|
|
|
if (msg < now) _exit(-1);
|
2016-01-21 18:59:25 +00:00
|
|
|
if (msg > now) {
|
|
|
|
now = msg;
|
|
|
|
now.tv_sec += 30;
|
|
|
|
msg = log_time(android_log_clockid());
|
|
|
|
if (now > msg) {
|
|
|
|
now = msg;
|
|
|
|
--now.tv_sec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
now.tv_sec -= 120; // inactive, reach further back!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content_wrap) {
|
|
|
|
dump_log_msg("wrap", &msg_wrap, 3, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content_timeout) {
|
|
|
|
dump_log_msg("timeout", &msg_timeout, 3, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content_wrap || !content_timeout) {
|
|
|
|
fprintf(stderr, "now=%" PRIu32 ".%09" PRIu32 "\n",
|
|
|
|
now.tv_sec, now.tv_nsec);
|
|
|
|
}
|
|
|
|
|
2015-12-01 16:57:53 +00:00
|
|
|
EXPECT_TRUE(written);
|
|
|
|
EXPECT_FALSE(content_wrap);
|
|
|
|
EXPECT_EQ(0U, alarm_wrap);
|
|
|
|
EXPECT_TRUE(content_timeout);
|
|
|
|
EXPECT_NE(0U, alarm_timeout);
|
2016-12-27 21:30:03 +00:00
|
|
|
|
|
|
|
_exit(!written + content_wrap + alarm_wrap + !content_timeout + !alarm_timeout);
|
2015-12-01 16:57:53 +00:00
|
|
|
}
|
2016-02-23 16:55:43 +00:00
|
|
|
|
|
|
|
// b/27242723 confirmed fixed
|
|
|
|
TEST(logd, SNDTIMEO) {
|
|
|
|
static const unsigned sndtimeo = LOGD_SNDTIMEO; // <sigh> it has to be done!
|
|
|
|
static const unsigned sleep_time = sndtimeo + 3;
|
|
|
|
static const unsigned alarm_time = sleep_time + 5;
|
|
|
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
ASSERT_TRUE((fd = socket_local_client("logdr",
|
|
|
|
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
|
|
SOCK_SEQPACKET)) > 0);
|
|
|
|
|
|
|
|
struct sigaction ignore, old_sigaction;
|
|
|
|
memset(&ignore, 0, sizeof(ignore));
|
|
|
|
ignore.sa_handler = caught_signal;
|
|
|
|
sigemptyset(&ignore.sa_mask);
|
|
|
|
sigaction(SIGALRM, &ignore, &old_sigaction);
|
|
|
|
unsigned int old_alarm = alarm(alarm_time);
|
|
|
|
|
|
|
|
static const char ask[] = "stream lids=0,1,2,3,4,5,6"; // all sources
|
|
|
|
bool reader_requested = write(fd, ask, sizeof(ask)) == sizeof(ask);
|
|
|
|
EXPECT_TRUE(reader_requested);
|
|
|
|
|
|
|
|
log_msg msg;
|
|
|
|
bool read_one = recv(fd, msg.buf, sizeof(msg), 0) > 0;
|
|
|
|
|
|
|
|
EXPECT_TRUE(read_one);
|
|
|
|
if (read_one) {
|
|
|
|
dump_log_msg("user", &msg, 3, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf (stderr, "Sleep for >%d seconds logd SO_SNDTIMEO ...\n", sndtimeo);
|
|
|
|
sleep(sleep_time);
|
|
|
|
|
|
|
|
// flush will block if we did not trigger. if it did, last entry returns 0
|
|
|
|
int recv_ret;
|
|
|
|
do {
|
|
|
|
recv_ret = recv(fd, msg.buf, sizeof(msg), 0);
|
|
|
|
} while (recv_ret > 0);
|
|
|
|
int save_errno = (recv_ret < 0) ? errno : 0;
|
|
|
|
|
|
|
|
EXPECT_NE(0U, alarm(old_alarm));
|
|
|
|
sigaction(SIGALRM, &old_sigaction, NULL);
|
|
|
|
|
|
|
|
EXPECT_EQ(0, recv_ret);
|
|
|
|
if (recv_ret > 0) {
|
|
|
|
dump_log_msg("user", &msg, 3, -1);
|
|
|
|
}
|
|
|
|
EXPECT_EQ(0, save_errno);
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
}
|
2016-12-13 18:31:29 +00:00
|
|
|
|
2016-09-12 21:51:54 +00:00
|
|
|
TEST(logd, getEventTag_list) {
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
char buffer[256];
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
snprintf(buffer, sizeof(buffer), "getEventTag name=*");
|
|
|
|
send_to_control(buffer, sizeof(buffer));
|
|
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
char *cp;
|
|
|
|
long ret = strtol(buffer, &cp, 10);
|
|
|
|
EXPECT_GT(ret, 4096);
|
|
|
|
#else
|
|
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-02-22 00:19:08 +00:00
|
|
|
TEST(logd, getEventTag_42) {
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
char buffer[256];
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
snprintf(buffer, sizeof(buffer), "getEventTag id=42");
|
|
|
|
send_to_control(buffer, sizeof(buffer));
|
|
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
char *cp;
|
|
|
|
long ret = strtol(buffer, &cp, 10);
|
|
|
|
EXPECT_GT(ret, 16);
|
|
|
|
EXPECT_TRUE(strstr(buffer, "\t(to life the universe etc|3)") != NULL);
|
|
|
|
EXPECT_TRUE(strstr(buffer, "answer") != NULL);
|
|
|
|
#else
|
|
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-09-12 21:51:54 +00:00
|
|
|
TEST(logd, getEventTag_newentry) {
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
char buffer[256];
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
log_time now(CLOCK_MONOTONIC);
|
|
|
|
char name[64];
|
|
|
|
snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
|
|
|
|
snprintf(buffer, sizeof(buffer),
|
|
|
|
"getEventTag name=%s format=\"(new|1)\"", name);
|
|
|
|
send_to_control(buffer, sizeof(buffer));
|
|
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
char *cp;
|
|
|
|
long ret = strtol(buffer, &cp, 10);
|
|
|
|
EXPECT_GT(ret, 16);
|
|
|
|
EXPECT_TRUE(strstr(buffer, "\t(new|1)") != NULL);
|
|
|
|
EXPECT_TRUE(strstr(buffer, name) != NULL);
|
|
|
|
// ToDo: also look for this in /data/misc/logd/event-log-tags and
|
|
|
|
// /dev/event-log-tags.
|
|
|
|
#else
|
|
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-12-13 18:31:29 +00:00
|
|
|
static inline int32_t get4LE(const char* src)
|
|
|
|
{
|
|
|
|
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
|
|
|
}
|
|
|
|
|
|
|
|
void __android_log_btwrite_multiple__helper(int count) {
|
|
|
|
log_time ts(CLOCK_MONOTONIC);
|
|
|
|
|
|
|
|
log_time ts1(CLOCK_MONOTONIC);
|
|
|
|
|
2016-12-27 21:30:03 +00:00
|
|
|
// We fork to create a unique pid for the submitted log messages
|
|
|
|
// so that we do not collide with the other _multiple_ tests.
|
|
|
|
|
2016-12-13 18:31:29 +00:00
|
|
|
pid_t pid = fork();
|
|
|
|
|
|
|
|
if (pid == 0) {
|
|
|
|
// child
|
|
|
|
for (int i = count; i; --i) {
|
|
|
|
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
|
|
|
|
usleep(100);
|
|
|
|
}
|
|
|
|
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
|
|
|
|
usleep(1000000);
|
|
|
|
|
|
|
|
_exit(0);
|
|
|
|
}
|
|
|
|
|
2016-12-27 21:30:03 +00:00
|
|
|
siginfo_t info = {};
|
2016-12-13 18:31:29 +00:00
|
|
|
ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
|
2016-12-27 21:30:03 +00:00
|
|
|
ASSERT_EQ(0, info.si_status);
|
|
|
|
|
|
|
|
struct logger_list *logger_list;
|
|
|
|
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
|
|
|
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)));
|
2016-12-13 18:31:29 +00:00
|
|
|
|
|
|
|
int expected_count = (count < 2) ? count : 2;
|
|
|
|
int expected_chatty_count = (count <= 2) ? 0 : 1;
|
2017-01-23 22:20:31 +00:00
|
|
|
int expected_identical_count = (count < 2) ? 0 : (count - 2);
|
|
|
|
static const int expected_expire_count = 0;
|
2016-12-13 18:31:29 +00:00
|
|
|
|
|
|
|
count = 0;
|
|
|
|
int second_count = 0;
|
|
|
|
int chatty_count = 0;
|
2017-01-23 22:20:31 +00:00
|
|
|
int identical_count = 0;
|
2016-12-13 18:31:29 +00:00
|
|
|
int expire_count = 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.entry.len < (4 + 1 + 8)) ||
|
|
|
|
(log_msg.id() != LOG_ID_EVENTS)) continue;
|
|
|
|
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
if (!eventData) continue;
|
|
|
|
|
|
|
|
uint32_t tag = get4LE(eventData);
|
|
|
|
|
|
|
|
if ((eventData[4] == EVENT_TYPE_LONG) && (log_msg.entry.len == (4 + 1 + 8))) {
|
|
|
|
if (tag != 0) continue;
|
|
|
|
|
|
|
|
log_time tx(eventData + 4 + 1);
|
|
|
|
if (ts == tx) {
|
|
|
|
++count;
|
|
|
|
} else if (ts1 == tx) {
|
|
|
|
++second_count;
|
|
|
|
}
|
|
|
|
} else if (eventData[4] == EVENT_TYPE_STRING) {
|
2017-01-03 22:00:19 +00:00
|
|
|
if (tag != CHATTY_LOG_TAG) continue;
|
2016-12-13 18:31:29 +00:00
|
|
|
++chatty_count;
|
|
|
|
// int len = get4LE(eventData + 4 + 1);
|
2017-01-03 22:00:19 +00:00
|
|
|
log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
|
2017-01-23 22:20:31 +00:00
|
|
|
const char *cp;
|
|
|
|
if ((cp = strstr(eventData + 4 + 1 + 4, " identical "))) {
|
|
|
|
unsigned val = 0;
|
|
|
|
sscanf(cp, " identical %u lines", &val);
|
|
|
|
identical_count += val;
|
|
|
|
} else if ((cp = strstr(eventData + 4 + 1 + 4, " expire "))) {
|
|
|
|
unsigned val = 0;
|
|
|
|
sscanf(cp, " expire %u lines", &val);
|
|
|
|
expire_count += val;
|
|
|
|
}
|
2016-12-13 18:31:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-27 21:30:03 +00:00
|
|
|
android_logger_list_close(logger_list);
|
|
|
|
|
2016-12-13 18:31:29 +00:00
|
|
|
EXPECT_EQ(expected_count, count);
|
|
|
|
EXPECT_EQ(1, second_count);
|
|
|
|
EXPECT_EQ(expected_chatty_count, chatty_count);
|
2017-01-23 22:20:31 +00:00
|
|
|
EXPECT_EQ(expected_identical_count, identical_count);
|
2016-12-13 18:31:29 +00:00
|
|
|
EXPECT_EQ(expected_expire_count, expire_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, multiple_test_1) {
|
|
|
|
__android_log_btwrite_multiple__helper(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, multiple_test_2) {
|
|
|
|
__android_log_btwrite_multiple__helper(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, multiple_test_3) {
|
|
|
|
__android_log_btwrite_multiple__helper(3);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, multiple_test_10) {
|
|
|
|
__android_log_btwrite_multiple__helper(10);
|
|
|
|
}
|
2017-01-03 22:00:19 +00:00
|
|
|
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
// returns violating pid
|
|
|
|
static pid_t sepolicy_rate(unsigned rate, unsigned num) {
|
|
|
|
pid_t pid = fork();
|
|
|
|
|
|
|
|
if (pid) {
|
|
|
|
siginfo_t info = {};
|
|
|
|
if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return 0;
|
|
|
|
if (info.si_status) return 0;
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We may have DAC, but let's not have MAC
|
|
|
|
if (setcon("u:object_r:shell:s0") < 0) {
|
|
|
|
int save_errno = errno;
|
|
|
|
security_context_t context;
|
|
|
|
getcon(&context);
|
|
|
|
fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n",
|
|
|
|
context, strerror(save_errno));
|
|
|
|
freecon(context);
|
|
|
|
_exit(-1);
|
|
|
|
// NOTREACHED
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-01-09 20:43:44 +00:00
|
|
|
// The key here is we are root, but we are in u:r:shell:s0,
|
|
|
|
// and the directory does not provide us DAC access
|
|
|
|
// (eg: 0700 system system) so we trigger the pair dac_override
|
|
|
|
// and dac_read_search on every try to get past the message
|
|
|
|
// de-duper. We will also rotate the file name in the directory
|
|
|
|
// as another measure.
|
|
|
|
static const char file[] = "/data/backup/cannot_access_directory_%u";
|
|
|
|
static const unsigned avc_requests_per_access = 2;
|
|
|
|
|
|
|
|
rate /= avc_requests_per_access;
|
2017-01-03 22:00:19 +00:00
|
|
|
useconds_t usec;
|
|
|
|
if (rate == 0) {
|
|
|
|
rate = 1;
|
|
|
|
usec = 2000000;
|
|
|
|
} else {
|
|
|
|
usec = (1000000 + (rate / 2)) / rate;
|
|
|
|
}
|
2017-01-09 20:43:44 +00:00
|
|
|
num = (num + (avc_requests_per_access / 2)) / avc_requests_per_access;
|
2017-01-03 22:00:19 +00:00
|
|
|
|
|
|
|
if (usec < 2) usec = 2;
|
|
|
|
|
|
|
|
while (num > 0) {
|
2017-01-09 20:43:44 +00:00
|
|
|
if (access(android::base::StringPrintf(file, num).c_str(), F_OK) == 0) {
|
2017-01-03 22:00:19 +00:00
|
|
|
_exit(-1);
|
|
|
|
// NOTREACHED
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
usleep(usec);
|
|
|
|
--num;
|
|
|
|
}
|
|
|
|
_exit(0);
|
|
|
|
// NOTREACHED
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int count_avc(pid_t pid) {
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
if (pid == 0) return count;
|
|
|
|
|
|
|
|
struct logger_list *logger_list;
|
|
|
|
if (!(logger_list = android_logger_list_open(LOG_ID_EVENTS,
|
|
|
|
ANDROID_LOG_RDONLY |
|
|
|
|
ANDROID_LOG_NONBLOCK,
|
|
|
|
0,
|
|
|
|
pid))) return count;
|
|
|
|
for (;;) {
|
|
|
|
log_msg log_msg;
|
|
|
|
|
|
|
|
if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
|
|
|
|
|
|
|
|
if ((log_msg.entry.pid != pid) ||
|
|
|
|
(log_msg.entry.len < (4 + 1 + 8)) ||
|
|
|
|
(log_msg.id() != LOG_ID_EVENTS)) continue;
|
|
|
|
|
|
|
|
char *eventData = log_msg.msg();
|
|
|
|
if (!eventData) continue;
|
|
|
|
|
|
|
|
uint32_t tag = get4LE(eventData);
|
|
|
|
if (tag != AUDITD_LOG_TAG) continue;
|
|
|
|
|
|
|
|
if (eventData[4] != EVENT_TYPE_STRING) continue;
|
|
|
|
|
|
|
|
// int len = get4LE(eventData + 4 + 1);
|
|
|
|
log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
|
2017-01-09 20:43:44 +00:00
|
|
|
const char *cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
|
2017-01-03 22:00:19 +00:00
|
|
|
if (!cp) continue;
|
|
|
|
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
|
|
|
|
android_logger_list_close(logger_list);
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TEST(logd, sepolicy_rate_limiter_maximum) {
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
static const int rate = AUDIT_RATE_LIMIT_MAX;
|
|
|
|
static const int duration = 2;
|
|
|
|
// Two seconds of a liveable sustained rate
|
|
|
|
EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
|
|
|
|
#else
|
|
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, sepolicy_rate_limiter_sub_burst) {
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
// maximum period below half way between sustainable and burst rate.
|
|
|
|
static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
|
|
|
|
(AUDIT_RATE_LIMIT_DEFAULT +
|
|
|
|
AUDIT_RATE_LIMIT_MAX)) +
|
|
|
|
1) / 2;
|
|
|
|
static const int rate = (threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
|
|
|
|
static const int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
|
|
|
|
EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
|
|
|
|
#else
|
|
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logd, sepolicy_rate_limiter_spam) {
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
// maximum period of double the maximum burst rate
|
|
|
|
static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
|
|
|
|
(AUDIT_RATE_LIMIT_DEFAULT +
|
|
|
|
AUDIT_RATE_LIMIT_MAX)) +
|
|
|
|
1) / 2;
|
|
|
|
static const int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
|
|
|
|
static const int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
|
|
|
|
EXPECT_GE(((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) /
|
|
|
|
100, // +15% margin
|
|
|
|
count_avc(sepolicy_rate(rate, rate * duration)));
|
|
|
|
// give logd another 3 seconds to react to the burst before checking
|
|
|
|
sepolicy_rate(rate, rate * 3);
|
|
|
|
// maximum period at double the maximum burst rate (spam filter kicked in)
|
2017-01-09 20:43:44 +00:00
|
|
|
EXPECT_GE(threshold * 2,
|
2017-01-03 22:00:19 +00:00
|
|
|
count_avc(sepolicy_rate(rate,
|
|
|
|
rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
|
|
|
|
// cool down, and check unspammy rate still works
|
|
|
|
sleep(2);
|
|
|
|
EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ to be lost
|
|
|
|
count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
|
|
|
|
#else
|
|
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
|
|
#endif
|
|
|
|
}
|