#pragma once
#ifdef _WIN32
#ifdef ERROR
#undef ERROR
#endif
#endif
#include <functional>
#include <memory>
#include <ostream>
#include "android-base/errno_restorer.h"
#include "android-base/macros.h"
#ifdef _LOG_TAG_INTERNAL
#error "_LOG_TAG_INTERNAL must not be defined"
#endif
#ifdef LOG_TAG
#define _LOG_TAG_INTERNAL LOG_TAG
#else
#define _LOG_TAG_INTERNAL nullptr
#endif
namespace android {
namespace base {
enum LogSeverity {
VERBOSE,
DEBUG,
INFO,
WARNING,
ERROR,
FATAL_WITHOUT_ABORT, FATAL,
};
enum LogId {
DEFAULT,
MAIN,
SYSTEM,
RADIO,
CRASH,
};
using LogFunction = std::function<void(LogId ,
LogSeverity ,
const char* ,
const char* ,
unsigned int ,
const char* )>;
using AbortFunction = std::function<void(const char* )>;
void KernelLogger(LogId log_buffer_id, LogSeverity severity, const char* tag, const char* file, unsigned int line, const char* message);
void StderrLogger(LogId log_buffer_id, LogSeverity severity, const char* tag, const char* file, unsigned int line, const char* message);
void StdioLogger(LogId log_buffer_id, LogSeverity severity, const char* tag, const char* file, unsigned int line, const char* message);
void DefaultAborter(const char* abort_message);
void SetDefaultTag(const std::string& tag);
class LogdLogger {
public:
explicit LogdLogger(LogId default_log_id = android::base::MAIN);
void operator()(LogId, LogSeverity, const char* tag, const char* file,
unsigned int line, const char* message);
private:
LogId default_log_id_;
};
#ifdef __ANDROID__
#define INIT_LOGGING_DEFAULT_LOGGER LogdLogger()
#else
#define INIT_LOGGING_DEFAULT_LOGGER StderrLogger
#endif
void InitLogging(char* argv[],
LogFunction&& logger = INIT_LOGGING_DEFAULT_LOGGER,
AbortFunction&& aborter = DefaultAborter);
#undef INIT_LOGGING_DEFAULT_LOGGER
LogFunction SetLogger(LogFunction&& logger);
AbortFunction SetAborter(AbortFunction&& aborter);
#define SEVERITY_LAMBDA(severity) ([&]() { \
using ::android::base::VERBOSE; \
using ::android::base::DEBUG; \
using ::android::base::INFO; \
using ::android::base::WARNING; \
using ::android::base::ERROR; \
using ::android::base::FATAL_WITHOUT_ABORT; \
using ::android::base::FATAL; \
return (severity); }())
#ifdef __clang_analyzer__
#define ABORT_AFTER_LOG_FATAL for (;; abort())
struct LogAbortAfterFullExpr {
~LogAbortAfterFullExpr() __attribute__((noreturn)) { abort(); }
explicit operator bool() const { return false; }
};
#define ABORT_AFTER_LOG_EXPR_IF(c, x) (((c) && ::android::base::LogAbortAfterFullExpr()) || (x))
#define MUST_LOG_MESSAGE(severity) (SEVERITY_LAMBDA(severity) == ::android::base::FATAL)
#else
#define ABORT_AFTER_LOG_FATAL
#define ABORT_AFTER_LOG_EXPR_IF(c, x) (x)
#define MUST_LOG_MESSAGE(severity) false
#endif
#define ABORT_AFTER_LOG_FATAL_EXPR(x) ABORT_AFTER_LOG_EXPR_IF(true, x)
#define WOULD_LOG(severity) \
(UNLIKELY(::android::base::ShouldLog(SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL)) || \
MUST_LOG_MESSAGE(severity))
#define LOG_STREAM(severity) \
::android::base::LogMessage(__FILE__, __LINE__, SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, \
-1) \
.stream()
#define LOG(severity) LOGGING_PREAMBLE(severity) && LOG_STREAM(severity)
#define LOGGING_PREAMBLE(severity) \
(WOULD_LOG(severity) && \
ABORT_AFTER_LOG_EXPR_IF((SEVERITY_LAMBDA(severity)) == ::android::base::FATAL, true) && \
::android::base::ErrnoRestorer())
#define PLOG(severity) \
LOGGING_PREAMBLE(severity) && \
::android::base::LogMessage(__FILE__, __LINE__, SEVERITY_LAMBDA(severity), \
_LOG_TAG_INTERNAL, errno) \
.stream()
#define UNIMPLEMENTED(level) \
LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
#define CHECK(x) \
LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) || \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, _LOG_TAG_INTERNAL, \
-1) \
.stream() \
<< "Check failed: " #x << " "
#define CHECK_OP(LHS, RHS, OP) \
for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \
UNLIKELY(!(_values.lhs.v OP _values.rhs.v)); \
) \
ABORT_AFTER_LOG_FATAL \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \
.stream() \
<< "Check failed: " << #LHS << " " << #OP << " " << #RHS << " (" #LHS "=" \
<< ::android::base::LogNullGuard<decltype(_values.lhs.v)>::Guard(_values.lhs.v) \
<< ", " #RHS "=" \
<< ::android::base::LogNullGuard<decltype(_values.rhs.v)>::Guard(_values.rhs.v) \
<< ") "
#define CHECK_EQ(x, y) CHECK_OP(x, y, == )
#define CHECK_NE(x, y) CHECK_OP(x, y, != )
#define CHECK_LE(x, y) CHECK_OP(x, y, <= )
#define CHECK_LT(x, y) CHECK_OP(x, y, < )
#define CHECK_GE(x, y) CHECK_OP(x, y, >= )
#define CHECK_GT(x, y) CHECK_OP(x, y, > )
#define CHECK_STROP(s1, s2, sense) \
while (UNLIKELY((strcmp(s1, s2) == 0) != (sense))) \
ABORT_AFTER_LOG_FATAL \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, \
_LOG_TAG_INTERNAL, -1) \
.stream() \
<< "Check failed: " << "\"" << (s1) << "\"" \
<< ((sense) ? " == " : " != ") << "\"" << (s2) << "\""
#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
#define CHECK_PTHREAD_CALL(call, args, what) \
do { \
int rc = call args; \
if (rc != 0) { \
errno = rc; \
ABORT_AFTER_LOG_FATAL \
PLOG(FATAL) << #call << " failed for " << (what); \
} \
} while (false)
#if defined(NDEBUG) && !defined(__clang_analyzer__)
static constexpr bool kEnableDChecks = false;
#else
static constexpr bool kEnableDChecks = true;
#endif
#define DCHECK(x) \
if (::android::base::kEnableDChecks) CHECK(x)
#define DCHECK_EQ(x, y) \
if (::android::base::kEnableDChecks) CHECK_EQ(x, y)
#define DCHECK_NE(x, y) \
if (::android::base::kEnableDChecks) CHECK_NE(x, y)
#define DCHECK_LE(x, y) \
if (::android::base::kEnableDChecks) CHECK_LE(x, y)
#define DCHECK_LT(x, y) \
if (::android::base::kEnableDChecks) CHECK_LT(x, y)
#define DCHECK_GE(x, y) \
if (::android::base::kEnableDChecks) CHECK_GE(x, y)
#define DCHECK_GT(x, y) \
if (::android::base::kEnableDChecks) CHECK_GT(x, y)
#define DCHECK_STREQ(s1, s2) \
if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2)
#define DCHECK_STRNE(s1, s2) \
if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2)
namespace log_detail {
template <typename T> struct Storage {
template <typename U> explicit constexpr Storage(U&& u) : v(std::forward<U>(u)) {}
explicit Storage(const Storage& t) = delete;
explicit Storage(Storage&& t) = delete;
T v;
};
template <typename T> struct Storage<std::unique_ptr<T>> {
explicit constexpr Storage(const std::unique_ptr<T>& ptr) : v(ptr.get()) {}
const T* v;
};
template <typename T> struct Storage<std::shared_ptr<T>> {
explicit constexpr Storage(const std::shared_ptr<T>& ptr) : v(ptr.get()) {}
const T* v;
};
template <typename T> struct IsCharPointer {
using Pointee = std::remove_cv_t<std::remove_pointer_t<T>>;
static constexpr bool value = std::is_pointer_v<T> &&
(std::is_same_v<Pointee, char> || std::is_same_v<Pointee, signed char> ||
std::is_same_v<Pointee, unsigned char>);
};
template <typename LHS, typename RHS> struct StorageTypes {
static constexpr bool voidptr = IsCharPointer<LHS>::value && IsCharPointer<RHS>::value;
using LHSType = std::conditional_t<voidptr, const void*, LHS>;
using RHSType = std::conditional_t<voidptr, const void*, RHS>;
};
template <typename LHS, typename RHS>
struct EagerEvaluator {
template <typename A, typename B> constexpr EagerEvaluator(A&& l, B&& r)
: lhs(std::forward<A>(l)), rhs(std::forward<B>(r)) {}
const Storage<typename StorageTypes<LHS, RHS>::LHSType> lhs;
const Storage<typename StorageTypes<LHS, RHS>::RHSType> rhs;
};
}
template <typename T> struct LogNullGuard {
static const T& Guard(const T& v) { return v; }
};
template <> struct LogNullGuard<std::nullptr_t> {
static const char* Guard(const std::nullptr_t&) { return "(null)"; }
};
template <> struct LogNullGuard<char*> {
static const char* Guard(const char* v) { return v ? v : "(null)"; }
};
template <> struct LogNullGuard<const char*> {
static const char* Guard(const char* v) { return v ? v : "(null)"; }
};
template <typename LHS, typename RHS>
constexpr auto MakeEagerEvaluator(LHS&& lhs, RHS&& rhs) {
return log_detail::EagerEvaluator<std::decay_t<LHS>, std::decay_t<RHS>>(
std::forward<LHS>(lhs), std::forward<RHS>(rhs));
}
class LogMessageData;
class LogMessage {
public:
LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, const char* tag,
int error);
LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error);
~LogMessage();
std::ostream& stream();
static void LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
const char* msg);
private:
const std::unique_ptr<LogMessageData> data_;
DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
LogSeverity GetMinimumLogSeverity();
LogSeverity SetMinimumLogSeverity(LogSeverity new_severity);
bool ShouldLog(LogSeverity severity, const char* tag);
class ScopedLogSeverity {
public:
explicit ScopedLogSeverity(LogSeverity level);
~ScopedLogSeverity();
private:
LogSeverity old_;
};
} }
namespace std {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
#define OSTREAM_STRING_POINTER_USAGE_WARNING \
__attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning")))
inline OSTREAM_STRING_POINTER_USAGE_WARNING
std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer) {
return stream << static_cast<const void*>(string_pointer);
}
#pragma clang diagnostic pop
}