/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __ANDROID__ #include #endif #include "LogUtils.h" // For LOGD_SNDTIMEO. using android::base::unique_fd; #ifdef __ANDROID__ static bool write_command(int sock, const char* command) { // The command sent to logd must include the '\0' character at the end. size_t command_length = strlen(command) + 1; ssize_t bytes_written = TEMP_FAILURE_RETRY(write(sock, command, command_length)); if (bytes_written != static_cast(command_length)) { if (bytes_written == -1) { printf("Failed to send '%s' command: %s\n", command, strerror(errno)); } else { printf("Failed to send '%s' command: bytes written %zd, expected written %zu\n", command, bytes_written, command_length); } return false; } return true; } static bool write_command(int sock, const std::string& command) { return write_command(sock, command.c_str()); } static void send_to_control(const char* command, std::string& result) { unique_fd sock(socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)); ASSERT_LT(0, sock) << "Failed to open logd: " << strerror(errno); ASSERT_TRUE(write_command(sock, command)); result.clear(); while (true) { struct pollfd p = {.fd = sock, .events = POLLIN, .revents = 0}; // Timeout after 20 seconds. int ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20000)); ASSERT_TRUE(ret != -1) << "Poll call failed for command '" << command << "': " << strerror(errno); ASSERT_NE(0, ret) << "Timeout sending command '" << command << "'"; ASSERT_TRUE(p.revents & POLLIN) << "Command socket not readable for command '" << command << "'"; char buffer[256]; ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer))); ASSERT_GE(bytes_read, 0) << "Read failed for command '" << command << "': " << strerror(errno); result += std::string(buffer, bytes_read); if (bytes_read == 0 || static_cast(bytes_read) < sizeof(buffer)) { return; } } } #endif #ifdef LOGD_ENABLE_FLAKY_TESTS TEST(logd, statistics) { #ifdef __ANDROID__ // Drop cache so that any access problems can be discovered. if (!android::base::WriteStringToFile("3\n", "/proc/sys/vm/drop_caches")) { GTEST_LOG_(INFO) << "Could not open trigger dropping inode cache"; } std::string result; send_to_control("getStatistics 0 1 2 3 4", result); ASSERT_FALSE(result.empty()); EXPECT_NE(std::string::npos, result.find("\nChattiest UIDs in main ")); EXPECT_NE(std::string::npos, result.find("\nChattiest UIDs in radio ")); EXPECT_NE(std::string::npos, result.find("\nChattiest UIDs in system ")); EXPECT_NE(std::string::npos, result.find("\nChattiest UIDs in events ")); // Look for any u0_a or u0_a[0-9]+ values. If found, it indicates the // libpackagelistparser failed. static const char getpwuid_prefix[] = " u0_a"; size_t pos = 0; while ((pos = result.find(getpwuid_prefix, pos)) != std::string::npos) { // Check to see if the value following u0_a is all digits, or empty. size_t uid_name_pos = pos + strlen(getpwuid_prefix); size_t i = 0; while (isdigit(result[uid_name_pos + i])) { i++; } ASSERT_FALSE(isspace(result[uid_name_pos + i])) << "libpackagelistparser failed to pick up " << result.substr(uid_name_pos, i); pos = uid_name_pos + i; } #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } #endif #ifdef __ANDROID__ static void caught_signal(int /* signum */) { } static void dump_log_msg(const char* prefix, log_msg* msg, int lid) { std::cout << std::flush; std::cerr << std::flush; fflush(stdout); fflush(stderr); EXPECT_GE(msg->entry.hdr_size, sizeof(logger_entry)); fprintf(stderr, "%s: [%u] ", prefix, msg->len()); 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); lid = msg->entry.lid; 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; case 4: fprintf(stderr, "lid=crash "); break; case 5: fprintf(stderr, "lid=security "); break; case 6: fprintf(stderr, "lid=kernel "); break; 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(msg->msg()); if (!cp) { static const unsigned char garbage[] = ""; cp = const_cast(garbage); len = strlen(reinterpret_cast(garbage)); } 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) { if (*cp != '\n') { fprintf(stderr, "%c", *cp); } else { fprintf(stderr, "\\n"); } ++cp; --len; } fprintf(stderr, "\""); } else { fprintf(stderr, "%02x", *cp); } ++cp; if (--len) { fprintf(stderr, ", "); } } fprintf(stderr, "}\n"); fflush(stderr); } #endif // b/26447386 confirm fixed void timeout_negative([[maybe_unused]] const char* command) { #ifdef __ANDROID__ 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) { unique_fd fd( socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET)); ASSERT_LT(0, fd) << "Failed to open logdr: " << strerror(errno); struct sigaction ignore = {.sa_handler = caught_signal}; sigemptyset(&ignore.sa_mask); struct sigaction old_sigaction; sigaction(SIGALRM, &ignore, &old_sigaction); unsigned int old_alarm = alarm(3); written = write_command(fd, command); if (!written) { alarm(old_alarm); sigaction(SIGALRM, &old_sigaction, nullptr); continue; } // alarm triggers at 50% of the --wrap time out content_wrap = TEMP_FAILURE_RETRY(recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0)) > 0; alarm_wrap = alarm(5); // alarm triggers at 133% of the --wrap time out content_timeout = TEMP_FAILURE_RETRY(recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0)) > 0; if (!content_timeout) { // make sure we hit dumpAndClose content_timeout = TEMP_FAILURE_RETRY(recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0)) > 0; } if (old_alarm > 0) { unsigned int time_spent = 3 - alarm_wrap; if (old_alarm > time_spent + 1) { old_alarm -= time_spent; } else { old_alarm = 2; } } alarm_timeout = alarm(old_alarm); sigaction(SIGALRM, &old_sigaction, nullptr); if (content_wrap && alarm_wrap && content_timeout && alarm_timeout) { break; } } if (content_wrap) { dump_log_msg("wrap", &msg_wrap, -1); } if (content_timeout) { dump_log_msg("timeout", &msg_timeout, -1); } EXPECT_TRUE(written); EXPECT_TRUE(content_wrap); EXPECT_NE(0U, alarm_wrap); EXPECT_TRUE(content_timeout); EXPECT_NE(0U, alarm_timeout); #else command = nullptr; GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } 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"); } #ifdef LOGD_ENABLE_FLAKY_TESTS // b/26447386 refined behavior TEST(logd, timeout) { #ifdef __ANDROID__ // 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; } 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 = 5; log_time start(CLOCK_REALTIME); start.tv_sec -= 30; // reach back a moderate period of time while (--i) { unique_fd fd( socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET)); ASSERT_LT(0, fd) << "Failed to open logdr: " << strerror(errno); std::string ask = android::base::StringPrintf( "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%" PRIu32 ".%09" PRIu32, start.tv_sec, start.tv_nsec); struct sigaction ignore = {.sa_handler = caught_signal}; sigemptyset(&ignore.sa_mask); struct sigaction old_sigaction; sigaction(SIGALRM, &ignore, &old_sigaction); unsigned int old_alarm = alarm(3); written = write_command(fd, ask); if (!written) { alarm(old_alarm); sigaction(SIGALRM, &old_sigaction, nullptr); continue; } // alarm triggers at 50% of the --wrap time out content_wrap = TEMP_FAILURE_RETRY(recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0)) > 0; alarm_wrap = alarm(5); // alarm triggers at 133% of the --wrap time out content_timeout = TEMP_FAILURE_RETRY(recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0)) > 0; if (!content_timeout) { // make sure we hit dumpAndClose content_timeout = TEMP_FAILURE_RETRY(recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0)) > 0; } if (old_alarm > 0) { unsigned int time_spent = 3 - alarm_wrap; if (old_alarm > time_spent + 1) { old_alarm -= time_spent; } else { old_alarm = 2; } } alarm_timeout = alarm(old_alarm); sigaction(SIGALRM, &old_sigaction, nullptr); 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); if (msg < start) { fprintf(stderr, "%u.%09u < %u.%09u\n", msg_timeout.entry.sec, msg_timeout.entry.nsec, (unsigned)start.tv_sec, (unsigned)start.tv_nsec); _exit(-1); } if (msg > start) { start = msg; start.tv_sec += 30; log_time now = log_time(CLOCK_REALTIME); if (start > now) { start = now; --start.tv_sec; } } } else { start.tv_sec -= 120; // inactive, reach further back! } } if (content_wrap) { dump_log_msg("wrap", &msg_wrap, -1); } if (content_timeout) { dump_log_msg("timeout", &msg_timeout, -1); } if (content_wrap || !content_timeout) { fprintf(stderr, "start=%" PRIu32 ".%09" PRIu32 "\n", start.tv_sec, start.tv_nsec); } EXPECT_TRUE(written); EXPECT_FALSE(content_wrap); EXPECT_EQ(0U, alarm_wrap); EXPECT_TRUE(content_timeout); EXPECT_NE(0U, alarm_timeout); _exit(!written + content_wrap + alarm_wrap + !content_timeout + !alarm_timeout); #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } #endif #ifdef LOGD_ENABLE_FLAKY_TESTS // b/27242723 confirmed fixed TEST(logd, SNDTIMEO) { #ifdef __ANDROID__ static const unsigned sndtimeo = LOGD_SNDTIMEO; // it has to be done! static const unsigned sleep_time = sndtimeo + 3; static const unsigned alarm_time = sleep_time + 5; unique_fd fd(socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET)); ASSERT_LT(0, fd) << "Failed to open logdr: " << strerror(errno); struct sigaction ignore = {.sa_handler = caught_signal}; sigemptyset(&ignore.sa_mask); struct sigaction old_sigaction; sigaction(SIGALRM, &ignore, &old_sigaction); unsigned int old_alarm = alarm(alarm_time); // Stream all sources. ASSERT_TRUE(write_command(fd, "stream lids=0,1,2,3,4,5,6")); log_msg msg; bool read_one = TEMP_FAILURE_RETRY(recv(fd, msg.buf, sizeof(msg), 0)) > 0; EXPECT_TRUE(read_one); if (read_one) { dump_log_msg("user", &msg, -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 = TEMP_FAILURE_RETRY(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, nullptr); EXPECT_EQ(0, recv_ret); if (recv_ret > 0) { dump_log_msg("user", &msg, -1); } EXPECT_EQ(0, save_errno); #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } #endif TEST(logd, getEventTag_list) { #ifdef __ANDROID__ std::string result; send_to_control("getEventTag name=*", result); ASSERT_FALSE(result.empty()); char* cp; long ret = strtol(result.c_str(), &cp, 10); EXPECT_GT(ret, 4096) << "Command result: " << result; #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } TEST(logd, getEventTag_42) { #ifdef __ANDROID__ std::string result; send_to_control("getEventTag id=42", result); ASSERT_FALSE(result.empty()); char* cp; long ret = strtol(result.c_str(), &cp, 10); EXPECT_GT(ret, 16) << "Command result: " << result; EXPECT_NE(std::string::npos, result.find("\t(to life the universe etc|3)")) << "Command result: " << result; EXPECT_NE(std::string::npos, result.find("answer")) << "Command result: " << result; #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } TEST(logd, getEventTag_newentry) { #ifdef __ANDROID__ log_time now(CLOCK_MONOTONIC); std::string name; name = android::base::StringPrintf("a%" PRIu64, now.nsec()); std::string command; command = android::base::StringPrintf("getEventTag name=%s format=\"(new|1)\"", name.c_str()); std::string result; send_to_control(command.c_str(), result); ASSERT_FALSE(result.empty()); char* cp; long ret = strtol(result.c_str(), &cp, 10); EXPECT_GT(ret, 16) << "Command result: " << result; EXPECT_NE(std::string::npos, result.find("\t(new|1)")) << "Command result: " << result; EXPECT_NE(std::string::npos, result.find(name)) << "Command result: " << result; // 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 } TEST(logd, no_epipe) { #ifdef __ANDROID__ // Actually generating SIGPIPE in logd is racy, since we need to close the socket quicker than // logd finishes writing the data to it, so we try 5 times, which should be enough to trigger // SIGPIPE if logd isn't ignoring SIGPIPE for (int i = 0; i < 5; ++i) { unique_fd sock1( socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)); ASSERT_LT(0, sock1) << "Failed to open logd: " << strerror(errno); unique_fd sock2( socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)); ASSERT_LT(0, sock2) << "Failed to open logd: " << strerror(errno); std::string message = "getStatistics 0 1 2 3 4 5 6 7"; ASSERT_TRUE(write_command(sock1, message)); sock1.reset(); ASSERT_TRUE(write_command(sock2, message)); struct pollfd p = {.fd = sock2, .events = POLLIN, .revents = 0}; int ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000)); EXPECT_EQ(ret, 1); EXPECT_TRUE(p.revents & POLLIN); EXPECT_FALSE(p.revents & POLL_ERR); } #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } // Only AID_ROOT, AID_SYSTEM, and AID_LOG can set log sizes. Ensure that a different user, AID_BIN, // cannot set the log size. TEST(logd, logging_permissions) { #ifdef __ANDROID__ if (getuid() != 0) { GTEST_SKIP() << "This test requires root"; } auto child_main = [] { setgroups(0, nullptr); setgid(AID_BIN); setuid(AID_BIN); std::unique_ptr logger_list{ android_logger_list_alloc(0, 0, 0), &android_logger_list_free}; if (!logger_list) { _exit(1); } auto logger = android_logger_open(logger_list.get(), LOG_ID_MAIN); if (!logger) { _exit(2); } // This line should fail, so if it returns 0, we exit with an error. if (android_logger_set_log_size(logger, 2 * 1024 * 1024) == 0) { _exit(3); } _exit(EXIT_SUCCESS); }; ASSERT_EXIT(child_main(), testing::ExitedWithCode(0), ""); #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif }