2015-03-14 07:06:01 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 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.
|
|
|
|
*/
|
|
|
|
|
2015-12-05 07:00:26 +01:00
|
|
|
#include "android-base/logging.h"
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2015-08-14 05:09:29 +02:00
|
|
|
#include <libgen.h>
|
|
|
|
|
2015-09-18 04:36:10 +02:00
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <signal.h>
|
|
|
|
#endif
|
|
|
|
|
2015-03-14 07:06:01 +01:00
|
|
|
#include <regex>
|
|
|
|
#include <string>
|
base: reimagine line splitting in logger.cpp
Previously, we would split messages by line and call the logger
function for each line. We would hold a lock during this, to ensure
that multiple threads would not interleave their messages.
There are a few problems with this approach:
1) Using a lock is not efficient and is not fork safe
2) With APEX, there is one lock per instance of libbase, so we must
move the lock to a location where all instances can access it, or
perform the line splitting in a way that does not require the lock.
To solve these issues, we reimagine line splitting.
1) We move the lock out of the LogMessage::~LogMessage() and make it
the logger's responsibility to split lines, giving the logger the
option to lock or not.
2) We do not need any locks at all for StderrLogger.
Instead, we generate a single string that contains all of the lines
with their appropriate log header. A single write() call is used
to output this at once.
3) Logd handles log messages with newlines correctly, however it only
accepts up to a maximum size of log message. Therefore we
separate the incoming log message into chunks, delimited by new
lines, up to that maximum size, and send each of those to logd.
Note that this is the strategy used in
android.util.Log.printlns().
This should solve a majority of use cases, since the maximum size
that logd accepts is nearly 4K, while remaining lock free.
If interleaving messages absolutely must be avoided, a lock can
still be used given 1) above.
Bug: 65062446
Bug: 153824050
Test: logging, particularly multi-line stack traces, show correctly
Test: existing and new unit tests
Change-Id: Id0cb5669bee7f912da1e17f7010f0ee4c93be1e3
(cherry picked from commit 36d31c530dd1fcd04acb1dfc4dd436a9a67e0022)
2020-04-17 22:05:11 +02:00
|
|
|
#include <thread>
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2015-12-05 07:00:26 +01:00
|
|
|
#include "android-base/file.h"
|
base: reimagine line splitting in logger.cpp
Previously, we would split messages by line and call the logger
function for each line. We would hold a lock during this, to ensure
that multiple threads would not interleave their messages.
There are a few problems with this approach:
1) Using a lock is not efficient and is not fork safe
2) With APEX, there is one lock per instance of libbase, so we must
move the lock to a location where all instances can access it, or
perform the line splitting in a way that does not require the lock.
To solve these issues, we reimagine line splitting.
1) We move the lock out of the LogMessage::~LogMessage() and make it
the logger's responsibility to split lines, giving the logger the
option to lock or not.
2) We do not need any locks at all for StderrLogger.
Instead, we generate a single string that contains all of the lines
with their appropriate log header. A single write() call is used
to output this at once.
3) Logd handles log messages with newlines correctly, however it only
accepts up to a maximum size of log message. Therefore we
separate the incoming log message into chunks, delimited by new
lines, up to that maximum size, and send each of those to logd.
Note that this is the strategy used in
android.util.Log.printlns().
This should solve a majority of use cases, since the maximum size
that logd accepts is nearly 4K, while remaining lock free.
If interleaving messages absolutely must be avoided, a lock can
still be used given 1) above.
Bug: 65062446
Bug: 153824050
Test: logging, particularly multi-line stack traces, show correctly
Test: existing and new unit tests
Change-Id: Id0cb5669bee7f912da1e17f7010f0ee4c93be1e3
(cherry picked from commit 36d31c530dd1fcd04acb1dfc4dd436a9a67e0022)
2020-04-17 22:05:11 +02:00
|
|
|
#include "android-base/scopeguard.h"
|
2015-12-05 07:00:26 +01:00
|
|
|
#include "android-base/stringprintf.h"
|
|
|
|
#include "android-base/test_utils.h"
|
2015-03-14 07:06:01 +01:00
|
|
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name)
|
|
|
|
#else
|
|
|
|
#define HOST_TEST(suite, name) TEST(suite, name)
|
|
|
|
#endif
|
|
|
|
|
2015-09-18 04:36:10 +02:00
|
|
|
#if defined(_WIN32)
|
|
|
|
static void ExitSignalAbortHandler(int) {
|
|
|
|
_exit(3);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void SuppressAbortUI() {
|
|
|
|
#if defined(_WIN32)
|
|
|
|
// We really just want to call _set_abort_behavior(0, _CALL_REPORTFAULT) to
|
|
|
|
// suppress the Windows Error Reporting dialog box, but that API is not
|
|
|
|
// available in the OS-supplied C Runtime, msvcrt.dll, that we currently
|
|
|
|
// use (it is available in the Visual Studio C runtime).
|
|
|
|
//
|
|
|
|
// Instead, we setup a SIGABRT handler, which is called in abort() right
|
|
|
|
// before calling Windows Error Reporting. In the handler, we exit the
|
|
|
|
// process just like abort() does.
|
|
|
|
ASSERT_NE(SIG_ERR, signal(SIGABRT, ExitSignalAbortHandler));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-03-27 19:20:14 +01:00
|
|
|
TEST(logging, CHECK) {
|
2015-09-18 04:36:10 +02:00
|
|
|
ASSERT_DEATH({SuppressAbortUI(); CHECK(false);}, "Check failed: false ");
|
2015-03-14 07:06:01 +01:00
|
|
|
CHECK(true);
|
|
|
|
|
2015-09-18 04:36:10 +02:00
|
|
|
ASSERT_DEATH({SuppressAbortUI(); CHECK_EQ(0, 1);}, "Check failed: 0 == 1 ");
|
2015-03-14 07:06:01 +01:00
|
|
|
CHECK_EQ(0, 0);
|
|
|
|
|
2015-09-18 04:36:10 +02:00
|
|
|
ASSERT_DEATH({SuppressAbortUI(); CHECK_STREQ("foo", "bar");},
|
|
|
|
R"(Check failed: "foo" == "bar")");
|
2015-03-14 07:06:01 +01:00
|
|
|
CHECK_STREQ("foo", "foo");
|
2015-09-18 04:36:10 +02:00
|
|
|
|
|
|
|
// Test whether CHECK() and CHECK_STREQ() have a dangling if with no else.
|
|
|
|
bool flag = false;
|
|
|
|
if (true)
|
|
|
|
CHECK(true);
|
|
|
|
else
|
|
|
|
flag = true;
|
|
|
|
EXPECT_FALSE(flag) << "CHECK macro probably has a dangling if with no else";
|
|
|
|
|
|
|
|
flag = false;
|
|
|
|
if (true)
|
|
|
|
CHECK_STREQ("foo", "foo");
|
|
|
|
else
|
|
|
|
flag = true;
|
|
|
|
EXPECT_FALSE(flag) << "CHECK_STREQ probably has a dangling if with no else";
|
2015-03-14 07:06:01 +01:00
|
|
|
}
|
|
|
|
|
2016-09-13 19:44:46 +02:00
|
|
|
TEST(logging, DCHECK) {
|
|
|
|
if (android::base::kEnableDChecks) {
|
|
|
|
ASSERT_DEATH({SuppressAbortUI(); DCHECK(false);}, "DCheck failed: false ");
|
|
|
|
}
|
|
|
|
DCHECK(true);
|
|
|
|
|
|
|
|
if (android::base::kEnableDChecks) {
|
|
|
|
ASSERT_DEATH({SuppressAbortUI(); DCHECK_EQ(0, 1);}, "DCheck failed: 0 == 1 ");
|
|
|
|
}
|
|
|
|
DCHECK_EQ(0, 0);
|
|
|
|
|
|
|
|
if (android::base::kEnableDChecks) {
|
|
|
|
ASSERT_DEATH({SuppressAbortUI(); DCHECK_STREQ("foo", "bar");},
|
|
|
|
R"(DCheck failed: "foo" == "bar")");
|
|
|
|
}
|
|
|
|
DCHECK_STREQ("foo", "foo");
|
|
|
|
|
|
|
|
// No testing whether we have a dangling else, possibly. That's inherent to the if (constexpr)
|
|
|
|
// setup we intentionally chose to force type-checks of debug code even in release builds (so
|
|
|
|
// we don't get more bit-rot).
|
|
|
|
}
|
|
|
|
|
2016-09-22 19:15:01 +02:00
|
|
|
|
2016-09-24 01:37:12 +02:00
|
|
|
#define CHECK_WOULD_LOG_DISABLED(severity) \
|
|
|
|
static_assert(android::base::severity < android::base::FATAL, "Bad input"); \
|
|
|
|
for (size_t i = static_cast<size_t>(android::base::severity) + 1; \
|
|
|
|
i <= static_cast<size_t>(android::base::FATAL); \
|
|
|
|
++i) { \
|
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
|
|
|
|
EXPECT_FALSE(WOULD_LOG(severity)) << i; \
|
|
|
|
} \
|
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
|
|
|
|
EXPECT_FALSE(WOULD_LOG(::android::base::severity)) << i; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
|
|
|
|
#define CHECK_WOULD_LOG_ENABLED(severity) \
|
|
|
|
for (size_t i = static_cast<size_t>(android::base::VERBOSE); \
|
|
|
|
i <= static_cast<size_t>(android::base::severity); \
|
|
|
|
++i) { \
|
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
|
|
|
|
EXPECT_TRUE(WOULD_LOG(severity)) << i; \
|
|
|
|
} \
|
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
|
|
|
|
EXPECT_TRUE(WOULD_LOG(::android::base::severity)) << i; \
|
|
|
|
} \
|
|
|
|
} \
|
2016-09-22 19:15:01 +02:00
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_FATAL) {
|
|
|
|
CHECK_WOULD_LOG_ENABLED(FATAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_enabled) {
|
|
|
|
CHECK_WOULD_LOG_ENABLED(FATAL_WITHOUT_ABORT);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_ERROR_disabled) {
|
|
|
|
CHECK_WOULD_LOG_DISABLED(ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_ERROR_enabled) {
|
|
|
|
CHECK_WOULD_LOG_ENABLED(ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_WARNING_disabled) {
|
|
|
|
CHECK_WOULD_LOG_DISABLED(WARNING);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_WARNING_enabled) {
|
|
|
|
CHECK_WOULD_LOG_ENABLED(WARNING);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_INFO_disabled) {
|
|
|
|
CHECK_WOULD_LOG_DISABLED(INFO);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_INFO_enabled) {
|
|
|
|
CHECK_WOULD_LOG_ENABLED(INFO);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_DEBUG_disabled) {
|
|
|
|
CHECK_WOULD_LOG_DISABLED(DEBUG);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_DEBUG_enabled) {
|
|
|
|
CHECK_WOULD_LOG_ENABLED(DEBUG);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_VERBOSE_disabled) {
|
|
|
|
CHECK_WOULD_LOG_DISABLED(VERBOSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, WOULD_LOG_VERBOSE_enabled) {
|
|
|
|
CHECK_WOULD_LOG_ENABLED(VERBOSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef CHECK_WOULD_LOG_DISABLED
|
|
|
|
#undef CHECK_WOULD_LOG_ENABLED
|
|
|
|
|
|
|
|
|
2017-11-30 03:06:11 +01:00
|
|
|
#if !defined(_WIN32)
|
2016-09-08 01:22:40 +02:00
|
|
|
static std::string make_log_pattern(android::base::LogSeverity severity,
|
|
|
|
const char* message) {
|
2016-09-07 19:10:50 +02:00
|
|
|
static const char log_characters[] = "VDIWEFF";
|
|
|
|
static_assert(arraysize(log_characters) - 1 == android::base::FATAL + 1,
|
|
|
|
"Mismatch in size of log_characters and values in LogSeverity");
|
2015-03-14 07:06:01 +01:00
|
|
|
char log_char = log_characters[severity];
|
2015-08-12 01:00:13 +02:00
|
|
|
std::string holder(__FILE__);
|
2015-03-14 07:06:01 +01:00
|
|
|
return android::base::StringPrintf(
|
2016-09-08 01:22:40 +02:00
|
|
|
"%c \\d+-\\d+ \\d+:\\d+:\\d+ \\s*\\d+ \\s*\\d+ %s:\\d+] %s",
|
2015-08-12 01:00:13 +02:00
|
|
|
log_char, basename(&holder[0]), message);
|
2015-03-14 07:06:01 +01:00
|
|
|
}
|
2017-11-30 03:06:11 +01:00
|
|
|
#endif
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2018-08-30 22:31:45 +02:00
|
|
|
static void CheckMessage(const std::string& output, android::base::LogSeverity severity,
|
2018-03-05 19:00:19 +01:00
|
|
|
const char* expected, const char* expected_tag = nullptr) {
|
2015-04-29 20:32:23 +02:00
|
|
|
// We can't usefully check the output of any of these on Windows because we
|
|
|
|
// don't have std::regex, but we can at least make sure we printed at least as
|
|
|
|
// many characters are in the log message.
|
2016-09-08 01:22:40 +02:00
|
|
|
ASSERT_GT(output.length(), strlen(expected));
|
|
|
|
ASSERT_NE(nullptr, strstr(output.c_str(), expected)) << output;
|
2018-03-05 19:00:19 +01:00
|
|
|
if (expected_tag != nullptr) {
|
|
|
|
ASSERT_NE(nullptr, strstr(output.c_str(), expected_tag)) << output;
|
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2015-04-29 20:32:23 +02:00
|
|
|
#if !defined(_WIN32)
|
2018-03-05 19:00:19 +01:00
|
|
|
std::string regex_str;
|
|
|
|
if (expected_tag != nullptr) {
|
|
|
|
regex_str.append(expected_tag);
|
|
|
|
regex_str.append(" ");
|
|
|
|
}
|
|
|
|
regex_str.append(make_log_pattern(severity, expected));
|
|
|
|
std::regex message_regex(regex_str);
|
2016-09-08 01:22:40 +02:00
|
|
|
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
|
2015-04-29 20:32:23 +02:00
|
|
|
#endif
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2018-08-30 22:31:45 +02:00
|
|
|
static void CheckMessage(CapturedStderr& cap, android::base::LogSeverity severity,
|
|
|
|
const char* expected, const char* expected_tag = nullptr) {
|
|
|
|
cap.Stop();
|
|
|
|
std::string output = cap.str();
|
|
|
|
return CheckMessage(output, severity, expected, expected_tag);
|
|
|
|
}
|
2016-09-24 01:37:12 +02:00
|
|
|
|
2018-08-30 22:31:45 +02:00
|
|
|
#define CHECK_LOG_STREAM_DISABLED(severity) \
|
|
|
|
{ \
|
2016-09-24 01:37:12 +02:00
|
|
|
android::base::ScopedLogSeverity sls1(android::base::FATAL); \
|
2018-08-30 22:31:45 +02:00
|
|
|
CapturedStderr cap1; \
|
|
|
|
LOG_STREAM(severity) << "foo bar"; \
|
|
|
|
cap1.Stop(); \
|
|
|
|
ASSERT_EQ("", cap1.str()); \
|
|
|
|
} \
|
|
|
|
{ \
|
2016-09-24 01:37:12 +02:00
|
|
|
android::base::ScopedLogSeverity sls1(android::base::FATAL); \
|
2018-08-30 22:31:45 +02:00
|
|
|
CapturedStderr cap1; \
|
|
|
|
LOG_STREAM(::android::base::severity) << "foo bar"; \
|
|
|
|
cap1.Stop(); \
|
|
|
|
ASSERT_EQ("", cap1.str()); \
|
|
|
|
}
|
2016-09-23 22:31:52 +02:00
|
|
|
|
|
|
|
#define CHECK_LOG_STREAM_ENABLED(severity) \
|
2016-09-24 01:37:12 +02:00
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(android::base::severity); \
|
|
|
|
CapturedStderr cap2; \
|
|
|
|
LOG_STREAM(severity) << "foobar"; \
|
|
|
|
CheckMessage(cap2, android::base::severity, "foobar"); \
|
|
|
|
} \
|
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(android::base::severity); \
|
|
|
|
CapturedStderr cap2; \
|
|
|
|
LOG_STREAM(::android::base::severity) << "foobar"; \
|
|
|
|
CheckMessage(cap2, android::base::severity, "foobar"); \
|
|
|
|
} \
|
2016-09-22 19:15:01 +02:00
|
|
|
|
2016-09-23 22:31:52 +02:00
|
|
|
TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(FATAL_WITHOUT_ABORT));
|
2016-09-23 22:31:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, LOG_STREAM_ERROR_disabled) {
|
|
|
|
CHECK_LOG_STREAM_DISABLED(ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, LOG_STREAM_ERROR_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(ERROR));
|
2016-09-23 22:31:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, LOG_STREAM_WARNING_disabled) {
|
|
|
|
CHECK_LOG_STREAM_DISABLED(WARNING);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, LOG_STREAM_WARNING_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(WARNING));
|
2016-09-23 22:31:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, LOG_STREAM_INFO_disabled) {
|
|
|
|
CHECK_LOG_STREAM_DISABLED(INFO);
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
|
|
|
|
2016-09-23 22:31:52 +02:00
|
|
|
TEST(logging, LOG_STREAM_INFO_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(INFO));
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
|
|
|
|
2016-09-23 22:31:52 +02:00
|
|
|
TEST(logging, LOG_STREAM_DEBUG_disabled) {
|
|
|
|
CHECK_LOG_STREAM_DISABLED(DEBUG);
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
|
|
|
|
2016-09-23 22:31:52 +02:00
|
|
|
TEST(logging, LOG_STREAM_DEBUG_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(DEBUG));
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
|
|
|
|
2016-09-23 22:31:52 +02:00
|
|
|
TEST(logging, LOG_STREAM_VERBOSE_disabled) {
|
|
|
|
CHECK_LOG_STREAM_DISABLED(VERBOSE);
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
|
|
|
|
2016-09-23 22:31:52 +02:00
|
|
|
TEST(logging, LOG_STREAM_VERBOSE_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(VERBOSE));
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
|
|
|
|
2016-09-23 22:31:52 +02:00
|
|
|
#undef CHECK_LOG_STREAM_DISABLED
|
|
|
|
#undef CHECK_LOG_STREAM_ENABLED
|
2016-09-22 19:15:01 +02:00
|
|
|
|
2018-08-30 22:31:45 +02:00
|
|
|
#define CHECK_LOG_DISABLED(severity) \
|
|
|
|
{ \
|
2016-09-24 01:37:12 +02:00
|
|
|
android::base::ScopedLogSeverity sls1(android::base::FATAL); \
|
2018-08-30 22:31:45 +02:00
|
|
|
CapturedStderr cap1; \
|
|
|
|
LOG(severity) << "foo bar"; \
|
|
|
|
cap1.Stop(); \
|
|
|
|
ASSERT_EQ("", cap1.str()); \
|
|
|
|
} \
|
|
|
|
{ \
|
2016-09-24 01:37:12 +02:00
|
|
|
android::base::ScopedLogSeverity sls1(android::base::FATAL); \
|
2018-08-30 22:31:45 +02:00
|
|
|
CapturedStderr cap1; \
|
|
|
|
LOG(::android::base::severity) << "foo bar"; \
|
|
|
|
cap1.Stop(); \
|
|
|
|
ASSERT_EQ("", cap1.str()); \
|
|
|
|
}
|
2016-09-22 19:15:01 +02:00
|
|
|
|
|
|
|
#define CHECK_LOG_ENABLED(severity) \
|
2016-09-24 01:37:12 +02:00
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(android::base::severity); \
|
|
|
|
CapturedStderr cap2; \
|
|
|
|
LOG(severity) << "foobar"; \
|
|
|
|
CheckMessage(cap2, android::base::severity, "foobar"); \
|
|
|
|
} \
|
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(android::base::severity); \
|
|
|
|
CapturedStderr cap2; \
|
|
|
|
LOG(::android::base::severity) << "foobar"; \
|
|
|
|
CheckMessage(cap2, android::base::severity, "foobar"); \
|
|
|
|
} \
|
2016-09-22 19:15:01 +02:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_FATAL) {
|
|
|
|
ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
|
2016-09-24 01:37:12 +02:00
|
|
|
ASSERT_DEATH({SuppressAbortUI(); LOG(::android::base::FATAL) << "foobar";}, "foobar");
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-07 19:10:50 +02:00
|
|
|
TEST(logging, LOG_FATAL_WITHOUT_ABORT_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(FATAL_WITHOUT_ABORT));
|
2016-09-07 19:10:50 +02:00
|
|
|
}
|
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_ERROR_disabled) {
|
|
|
|
CHECK_LOG_DISABLED(ERROR);
|
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_ERROR_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(ERROR));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_WARNING_disabled) {
|
|
|
|
CHECK_LOG_DISABLED(WARNING);
|
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_WARNING_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(WARNING));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_INFO_disabled) {
|
|
|
|
CHECK_LOG_DISABLED(INFO);
|
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_INFO_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(INFO));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_DEBUG_disabled) {
|
|
|
|
CHECK_LOG_DISABLED(DEBUG);
|
|
|
|
}
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_DEBUG_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(DEBUG));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_VERBOSE_disabled) {
|
|
|
|
CHECK_LOG_DISABLED(VERBOSE);
|
|
|
|
}
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_VERBOSE_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(VERBOSE));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2016-09-22 19:15:01 +02:00
|
|
|
#undef CHECK_LOG_DISABLED
|
|
|
|
#undef CHECK_LOG_ENABLED
|
|
|
|
|
2016-09-24 01:37:12 +02:00
|
|
|
TEST(logging, LOG_complex_param) {
|
2018-08-30 22:31:45 +02:00
|
|
|
#define CHECK_LOG_COMBINATION(use_scoped_log_severity_info, use_logging_severity_info) \
|
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls( \
|
|
|
|
(use_scoped_log_severity_info) ? ::android::base::INFO : ::android::base::WARNING); \
|
|
|
|
CapturedStderr cap; \
|
|
|
|
LOG((use_logging_severity_info) ? ::android::base::INFO : ::android::base::WARNING) \
|
|
|
|
<< "foobar"; \
|
|
|
|
if ((use_scoped_log_severity_info) || !(use_logging_severity_info)) { \
|
|
|
|
ASSERT_NO_FATAL_FAILURE(CheckMessage( \
|
|
|
|
cap, (use_logging_severity_info) ? ::android::base::INFO : ::android::base::WARNING, \
|
|
|
|
"foobar")); \
|
|
|
|
} else { \
|
|
|
|
cap.Stop(); \
|
|
|
|
ASSERT_EQ("", cap.str()); \
|
|
|
|
} \
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
|
|
|
|
2016-09-24 01:37:12 +02:00
|
|
|
CHECK_LOG_COMBINATION(false,false);
|
|
|
|
CHECK_LOG_COMBINATION(false,true);
|
|
|
|
CHECK_LOG_COMBINATION(true,false);
|
|
|
|
CHECK_LOG_COMBINATION(true,true);
|
2016-09-22 19:15:01 +02:00
|
|
|
|
2016-09-24 01:37:12 +02:00
|
|
|
#undef CHECK_LOG_COMBINATION
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_does_not_clobber_errno) {
|
|
|
|
CapturedStderr cap;
|
|
|
|
errno = 12345;
|
|
|
|
LOG(INFO) << (errno = 67890);
|
|
|
|
EXPECT_EQ(12345, errno) << "errno was not restored";
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::INFO, "67890"));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, PLOG_does_not_clobber_errno) {
|
|
|
|
CapturedStderr cap;
|
|
|
|
errno = 12345;
|
|
|
|
PLOG(INFO) << (errno = 67890);
|
|
|
|
EXPECT_EQ(12345, errno) << "errno was not restored";
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::INFO, "67890"));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, LOG_does_not_have_dangling_if) {
|
|
|
|
CapturedStderr cap; // So the logging below has no side-effects.
|
2015-09-18 04:36:10 +02:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
// Do the test two ways: once where we hypothesize that LOG()'s if
|
|
|
|
// will evaluate to true (when severity is high enough) and once when we
|
|
|
|
// expect it to evaluate to false (when severity is not high enough).
|
|
|
|
bool flag = false;
|
|
|
|
if (true)
|
|
|
|
LOG(INFO) << "foobar";
|
|
|
|
else
|
|
|
|
flag = true;
|
|
|
|
|
|
|
|
EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
|
|
|
|
|
|
|
|
flag = false;
|
|
|
|
if (true)
|
|
|
|
LOG(VERBOSE) << "foobar";
|
|
|
|
else
|
|
|
|
flag = true;
|
|
|
|
|
|
|
|
EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
|
2016-09-22 19:15:01 +02:00
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2018-08-30 22:31:45 +02:00
|
|
|
#define CHECK_PLOG_DISABLED(severity) \
|
|
|
|
{ \
|
2016-09-24 01:37:12 +02:00
|
|
|
android::base::ScopedLogSeverity sls1(android::base::FATAL); \
|
2018-08-30 22:31:45 +02:00
|
|
|
CapturedStderr cap1; \
|
|
|
|
PLOG(severity) << "foo bar"; \
|
|
|
|
cap1.Stop(); \
|
|
|
|
ASSERT_EQ("", cap1.str()); \
|
|
|
|
} \
|
|
|
|
{ \
|
2016-09-24 01:37:12 +02:00
|
|
|
android::base::ScopedLogSeverity sls1(android::base::FATAL); \
|
2018-08-30 22:31:45 +02:00
|
|
|
CapturedStderr cap1; \
|
|
|
|
PLOG(severity) << "foo bar"; \
|
|
|
|
cap1.Stop(); \
|
|
|
|
ASSERT_EQ("", cap1.str()); \
|
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
#define CHECK_PLOG_ENABLED(severity) \
|
2016-09-24 01:37:12 +02:00
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(android::base::severity); \
|
|
|
|
CapturedStderr cap2; \
|
|
|
|
errno = ENOENT; \
|
|
|
|
PLOG(severity) << "foobar"; \
|
|
|
|
CheckMessage(cap2, android::base::severity, "foobar: No such file or directory"); \
|
|
|
|
} \
|
|
|
|
{ \
|
|
|
|
android::base::ScopedLogSeverity sls2(android::base::severity); \
|
|
|
|
CapturedStderr cap2; \
|
|
|
|
errno = ENOENT; \
|
|
|
|
PLOG(severity) << "foobar"; \
|
|
|
|
CheckMessage(cap2, android::base::severity, "foobar: No such file or directory"); \
|
|
|
|
} \
|
2016-09-08 01:22:40 +02:00
|
|
|
|
2016-09-07 19:10:50 +02:00
|
|
|
TEST(logging, PLOG_FATAL) {
|
|
|
|
ASSERT_DEATH({SuppressAbortUI(); PLOG(FATAL) << "foobar";}, "foobar");
|
2016-09-24 01:37:12 +02:00
|
|
|
ASSERT_DEATH({SuppressAbortUI(); PLOG(::android::base::FATAL) << "foobar";}, "foobar");
|
2016-09-07 19:10:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, PLOG_FATAL_WITHOUT_ABORT_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(FATAL_WITHOUT_ABORT));
|
2016-09-07 19:10:50 +02:00
|
|
|
}
|
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, PLOG_ERROR_disabled) {
|
|
|
|
CHECK_PLOG_DISABLED(ERROR);
|
2015-03-14 07:06:01 +01:00
|
|
|
}
|
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, PLOG_ERROR_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(ERROR));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, PLOG_WARNING_disabled) {
|
|
|
|
CHECK_PLOG_DISABLED(WARNING);
|
|
|
|
}
|
2015-03-14 07:06:01 +01:00
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, PLOG_WARNING_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(WARNING));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, PLOG_INFO_disabled) {
|
|
|
|
CHECK_PLOG_DISABLED(INFO);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, PLOG_INFO_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(INFO));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, PLOG_DEBUG_disabled) {
|
|
|
|
CHECK_PLOG_DISABLED(DEBUG);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, PLOG_DEBUG_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(DEBUG));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, PLOG_VERBOSE_disabled) {
|
|
|
|
CHECK_PLOG_DISABLED(VERBOSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, PLOG_VERBOSE_enabled) {
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(VERBOSE));
|
2016-09-08 01:22:40 +02:00
|
|
|
}
|
|
|
|
|
2016-09-22 19:15:01 +02:00
|
|
|
#undef CHECK_PLOG_DISABLED
|
|
|
|
#undef CHECK_PLOG_ENABLED
|
|
|
|
|
|
|
|
|
2016-09-08 01:22:40 +02:00
|
|
|
TEST(logging, UNIMPLEMENTED) {
|
|
|
|
std::string expected = android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
CapturedStderr cap;
|
|
|
|
errno = ENOENT;
|
|
|
|
UNIMPLEMENTED(ERROR);
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::ERROR, expected.c_str()));
|
2015-03-14 07:06:01 +01:00
|
|
|
}
|
2016-09-08 20:03:58 +02:00
|
|
|
|
|
|
|
static void NoopAborter(const char* msg ATTRIBUTE_UNUSED) {
|
|
|
|
LOG(ERROR) << "called noop";
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(logging, LOG_FATAL_NOOP_ABORTER) {
|
2018-08-30 22:31:45 +02:00
|
|
|
CapturedStderr cap;
|
2016-09-08 20:03:58 +02:00
|
|
|
{
|
|
|
|
android::base::SetAborter(NoopAborter);
|
|
|
|
|
|
|
|
android::base::ScopedLogSeverity sls(android::base::ERROR);
|
|
|
|
LOG(FATAL) << "foobar";
|
2018-08-30 22:31:45 +02:00
|
|
|
cap.Stop();
|
2016-09-08 20:03:58 +02:00
|
|
|
|
|
|
|
android::base::SetAborter(android::base::DefaultAborter);
|
|
|
|
}
|
2018-08-30 22:31:45 +02:00
|
|
|
std::string output = cap.str();
|
|
|
|
ASSERT_NO_FATAL_FAILURE(CheckMessage(output, android::base::FATAL, "foobar"));
|
|
|
|
ASSERT_NO_FATAL_FAILURE(CheckMessage(output, android::base::ERROR, "called noop"));
|
2016-09-08 20:03:58 +02:00
|
|
|
|
|
|
|
ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
|
|
|
|
}
|
2016-10-05 04:17:07 +02:00
|
|
|
|
|
|
|
struct CountLineAborter {
|
|
|
|
static void CountLineAborterFunction(const char* msg) {
|
|
|
|
while (*msg != 0) {
|
|
|
|
if (*msg == '\n') {
|
|
|
|
newline_count++;
|
|
|
|
}
|
|
|
|
msg++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static size_t newline_count;
|
|
|
|
};
|
|
|
|
size_t CountLineAborter::newline_count = 0;
|
|
|
|
|
|
|
|
TEST(logging, LOG_FATAL_ABORTER_MESSAGE) {
|
|
|
|
CountLineAborter::newline_count = 0;
|
|
|
|
android::base::SetAborter(CountLineAborter::CountLineAborterFunction);
|
|
|
|
|
|
|
|
android::base::ScopedLogSeverity sls(android::base::ERROR);
|
|
|
|
CapturedStderr cap;
|
|
|
|
LOG(FATAL) << "foo\nbar";
|
|
|
|
|
base: reimagine line splitting in logger.cpp
Previously, we would split messages by line and call the logger
function for each line. We would hold a lock during this, to ensure
that multiple threads would not interleave their messages.
There are a few problems with this approach:
1) Using a lock is not efficient and is not fork safe
2) With APEX, there is one lock per instance of libbase, so we must
move the lock to a location where all instances can access it, or
perform the line splitting in a way that does not require the lock.
To solve these issues, we reimagine line splitting.
1) We move the lock out of the LogMessage::~LogMessage() and make it
the logger's responsibility to split lines, giving the logger the
option to lock or not.
2) We do not need any locks at all for StderrLogger.
Instead, we generate a single string that contains all of the lines
with their appropriate log header. A single write() call is used
to output this at once.
3) Logd handles log messages with newlines correctly, however it only
accepts up to a maximum size of log message. Therefore we
separate the incoming log message into chunks, delimited by new
lines, up to that maximum size, and send each of those to logd.
Note that this is the strategy used in
android.util.Log.printlns().
This should solve a majority of use cases, since the maximum size
that logd accepts is nearly 4K, while remaining lock free.
If interleaving messages absolutely must be avoided, a lock can
still be used given 1) above.
Bug: 65062446
Bug: 153824050
Test: logging, particularly multi-line stack traces, show correctly
Test: existing and new unit tests
Change-Id: Id0cb5669bee7f912da1e17f7010f0ee4c93be1e3
(cherry picked from commit 36d31c530dd1fcd04acb1dfc4dd436a9a67e0022)
2020-04-17 22:05:11 +02:00
|
|
|
EXPECT_EQ(CountLineAborter::newline_count, 1U);
|
2016-10-05 04:17:07 +02:00
|
|
|
}
|
2017-01-23 19:29:23 +01:00
|
|
|
|
|
|
|
__attribute__((constructor)) void TestLoggingInConstructor() {
|
|
|
|
LOG(ERROR) << "foobar";
|
|
|
|
}
|
2018-03-05 19:00:19 +01:00
|
|
|
|
2018-05-23 18:16:46 +02:00
|
|
|
TEST(logging, StdioLogger) {
|
2018-08-30 22:31:45 +02:00
|
|
|
CapturedStderr cap_err;
|
|
|
|
CapturedStdout cap_out;
|
|
|
|
android::base::SetLogger(android::base::StdioLogger);
|
|
|
|
LOG(INFO) << "out";
|
|
|
|
LOG(ERROR) << "err";
|
|
|
|
cap_err.Stop();
|
|
|
|
cap_out.Stop();
|
2018-05-23 18:16:46 +02:00
|
|
|
|
|
|
|
// For INFO we expect just the literal "out\n".
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_EQ("out\n", cap_out.str());
|
2018-05-23 18:16:46 +02:00
|
|
|
// Whereas ERROR logging includes the program name.
|
2018-08-30 22:31:45 +02:00
|
|
|
ASSERT_EQ(android::base::Basename(android::base::GetExecutablePath()) + ": err\n", cap_err.str());
|
2018-05-23 18:16:46 +02:00
|
|
|
}
|
base: reimagine line splitting in logger.cpp
Previously, we would split messages by line and call the logger
function for each line. We would hold a lock during this, to ensure
that multiple threads would not interleave their messages.
There are a few problems with this approach:
1) Using a lock is not efficient and is not fork safe
2) With APEX, there is one lock per instance of libbase, so we must
move the lock to a location where all instances can access it, or
perform the line splitting in a way that does not require the lock.
To solve these issues, we reimagine line splitting.
1) We move the lock out of the LogMessage::~LogMessage() and make it
the logger's responsibility to split lines, giving the logger the
option to lock or not.
2) We do not need any locks at all for StderrLogger.
Instead, we generate a single string that contains all of the lines
with their appropriate log header. A single write() call is used
to output this at once.
3) Logd handles log messages with newlines correctly, however it only
accepts up to a maximum size of log message. Therefore we
separate the incoming log message into chunks, delimited by new
lines, up to that maximum size, and send each of those to logd.
Note that this is the strategy used in
android.util.Log.printlns().
This should solve a majority of use cases, since the maximum size
that logd accepts is nearly 4K, while remaining lock free.
If interleaving messages absolutely must be avoided, a lock can
still be used given 1) above.
Bug: 65062446
Bug: 153824050
Test: logging, particularly multi-line stack traces, show correctly
Test: existing and new unit tests
Change-Id: Id0cb5669bee7f912da1e17f7010f0ee4c93be1e3
(cherry picked from commit 36d31c530dd1fcd04acb1dfc4dd436a9a67e0022)
2020-04-17 22:05:11 +02:00
|
|
|
|
|
|
|
TEST(logging, ForkSafe) {
|
|
|
|
#if !defined(_WIN32)
|
|
|
|
using namespace android::base;
|
|
|
|
SetLogger(
|
|
|
|
[&](LogId, LogSeverity, const char*, const char*, unsigned int, const char*) { sleep(3); });
|
|
|
|
|
|
|
|
auto guard = make_scope_guard([&] {
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
SetLogger(LogdLogger());
|
|
|
|
#else
|
|
|
|
SetLogger(StderrLogger);
|
|
|
|
#endif
|
|
|
|
});
|
|
|
|
|
|
|
|
auto thread = std::thread([] {
|
|
|
|
LOG(ERROR) << "This should sleep for 3 seconds, long enough to fork another process, if there "
|
|
|
|
"is no intervention";
|
|
|
|
});
|
|
|
|
thread.detach();
|
|
|
|
|
|
|
|
auto pid = fork();
|
|
|
|
ASSERT_NE(-1, pid);
|
|
|
|
|
|
|
|
if (pid == 0) {
|
|
|
|
// Reset the logger, so the next message doesn't sleep().
|
|
|
|
SetLogger([](LogId, LogSeverity, const char*, const char*, unsigned int, const char*) {});
|
|
|
|
LOG(ERROR) << "This should succeed in the child, only if libbase is forksafe.";
|
|
|
|
_exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for up to 3 seconds for the child to exit.
|
|
|
|
int tries = 3;
|
|
|
|
bool found_child = false;
|
|
|
|
while (tries-- > 0) {
|
|
|
|
auto result = waitpid(pid, nullptr, WNOHANG);
|
|
|
|
EXPECT_NE(-1, result);
|
|
|
|
if (result == pid) {
|
|
|
|
found_child = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sleep(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_TRUE(found_child);
|
|
|
|
|
|
|
|
// Kill the child if it did not exit.
|
|
|
|
if (!found_child) {
|
|
|
|
kill(pid, SIGKILL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|