Merge "Fix global finding logic."
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 83b9238..a6d7e31 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1125,8 +1125,8 @@
return false;
}
+ fwrite(buf, 1, sizeof(buf) - bytes_left, stdout);
fflush(stdout);
- WriteFdExactly(STDOUT_FILENO, buf, sizeof(buf) - bytes_left);
if (cur != buf && strstr(buf, "restarting") == nullptr) {
return true;
}
diff --git a/base/Android.bp b/base/Android.bp
index 8351461..b25d0df 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -56,6 +56,7 @@
"chrono_utils.cpp",
"cmsg.cpp",
"file.cpp",
+ "liblog_symbols.cpp",
"logging.cpp",
"mapped_file.cpp",
"parsebool.cpp",
@@ -68,6 +69,10 @@
"test_utils.cpp",
],
+ static: {
+ cflags: ["-DNO_LIBLOG_DLSYM"],
+ },
+
cppflags: ["-Wexit-time-destructors"],
shared_libs: ["liblog"],
target: {
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 3a9186a..7fd0182 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -85,7 +85,7 @@
INFO,
WARNING,
ERROR,
- FATAL_WITHOUT_ABORT,
+ FATAL_WITHOUT_ABORT, // For loggability tests, this is considered identical to FATAL.
FATAL,
};
@@ -93,6 +93,8 @@
DEFAULT,
MAIN,
SYSTEM,
+ RADIO,
+ CRASH,
};
using LogFunction = std::function<void(LogId, LogSeverity, const char*, const char*,
@@ -209,8 +211,8 @@
#define ABORT_AFTER_LOG_FATAL_EXPR(x) ABORT_AFTER_LOG_EXPR_IF(true, x)
// Defines whether the given severity will be logged or silently swallowed.
-#define WOULD_LOG(severity) \
- (UNLIKELY((SEVERITY_LAMBDA(severity)) >= ::android::base::GetMinimumLogSeverity()) || \
+#define WOULD_LOG(severity) \
+ (UNLIKELY(::android::base::ShouldLog(SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL)) || \
MUST_LOG_MESSAGE(severity))
// Get an ostream that can be used for logging at the given severity and to the default
@@ -442,6 +444,9 @@
// Set the minimum severity level for logging, returning the old severity.
LogSeverity SetMinimumLogSeverity(LogSeverity new_severity);
+// Return whether or not a log message with the associated tag should be logged.
+bool ShouldLog(LogSeverity severity, const char* tag);
+
// Allows to temporarily change the minimum severity level for logging.
class ScopedLogSeverity {
public:
@@ -460,9 +465,6 @@
// Emit a warning of ostream<< with std::string*. The intention was most likely to print *string.
//
// Note: for this to work, we need to have this in a namespace.
-// Note: lots of ifdef magic to make this work with Clang (platform) vs GCC (windows tools)
-// Note: using diagnose_if(true) under Clang and nothing under GCC/mingw as there is no common
-// attribute support.
// Note: using a pragma because "-Wgcc-compat" (included in "-Weverything") complains about
// diagnose_if.
// Note: to print the pointer, use "<< static_cast<const void*>(string_pointer)" instead.
@@ -472,8 +474,8 @@
#pragma clang diagnostic ignored "-Wgcc-compat"
#define OSTREAM_STRING_POINTER_USAGE_WARNING \
__attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning")))
-inline std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer)
- OSTREAM_STRING_POINTER_USAGE_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
diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp
new file mode 100644
index 0000000..d0e2eaa
--- /dev/null
+++ b/base/liblog_symbols.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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 "liblog_symbols.h"
+
+#if defined(__ANDROID__) && !defined(NO_LIBLOG_DLSYM)
+#include <dlfcn.h>
+#endif
+
+namespace android {
+namespace base {
+
+#if defined(__ANDROID__) && !defined(NO_LIBLOG_DLSYM)
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions() {
+ static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
+ void* liblog_handle = dlopen("liblog.so", RTLD_NOW);
+ if (liblog_handle == nullptr) {
+ return {};
+ }
+
+ LibLogFunctions real_liblog_functions = {};
+
+#define DLSYM(name) \
+ real_liblog_functions.name = \
+ reinterpret_cast<decltype(LibLogFunctions::name)>(dlsym(liblog_handle, #name)); \
+ if (real_liblog_functions.name == nullptr) { \
+ return {}; \
+ }
+
+ DLSYM(__android_log_set_logger)
+ DLSYM(__android_log_write_logger_data)
+ DLSYM(__android_log_logd_logger)
+ DLSYM(__android_log_stderr_logger)
+ DLSYM(__android_log_set_aborter)
+ DLSYM(__android_log_call_aborter)
+ DLSYM(__android_log_default_aborter)
+ DLSYM(__android_log_set_minimum_priority);
+ DLSYM(__android_log_get_minimum_priority);
+#undef DLSYM
+
+ return real_liblog_functions;
+ }();
+
+ return liblog_functions;
+}
+
+#else
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions() {
+ static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
+ return LibLogFunctions{
+ .__android_log_set_logger = __android_log_set_logger,
+ .__android_log_write_logger_data = __android_log_write_logger_data,
+ .__android_log_logd_logger = __android_log_logd_logger,
+ .__android_log_stderr_logger = __android_log_stderr_logger,
+ .__android_log_set_aborter = __android_log_set_aborter,
+ .__android_log_call_aborter = __android_log_call_aborter,
+ .__android_log_default_aborter = __android_log_default_aborter,
+ .__android_log_set_minimum_priority = __android_log_set_minimum_priority,
+ .__android_log_get_minimum_priority = __android_log_get_minimum_priority,
+ };
+ }();
+ return liblog_functions;
+}
+
+#endif
+
+} // namespace base
+} // namespace android
diff --git a/base/liblog_symbols.h b/base/liblog_symbols.h
new file mode 100644
index 0000000..c68fff6
--- /dev/null
+++ b/base/liblog_symbols.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <android/log.h>
+
+namespace android {
+namespace base {
+
+struct LibLogFunctions {
+ void (*__android_log_set_logger)(__android_logger_function logger);
+ void (*__android_log_write_logger_data)(struct __android_logger_data* logger_data,
+ const char* msg);
+
+ void (*__android_log_logd_logger)(const struct __android_logger_data* logger_data,
+ const char* msg);
+ void (*__android_log_stderr_logger)(const struct __android_logger_data* logger_data,
+ const char* message);
+
+ void (*__android_log_set_aborter)(__android_aborter_function aborter);
+ void (*__android_log_call_aborter)(const char* abort_message);
+ void (*__android_log_default_aborter)(const char* abort_message);
+ int (*__android_log_set_minimum_priority)(int priority);
+ int (*__android_log_get_minimum_priority)();
+};
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions();
+
+} // namespace base
+} // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
index b46abbf..508871d 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -36,15 +36,16 @@
#include <sys/uio.h>
#endif
+#include <atomic>
#include <iostream>
#include <limits>
#include <mutex>
+#include <optional>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
-// Headers for LogMessage::LogLine.
#include <android/log.h>
#ifdef __ANDROID__
#include <android/set_abort_message.h>
@@ -59,6 +60,8 @@
#include <android-base/strings.h>
#include <android-base/threads.h>
+#include "liblog_symbols.h"
+
namespace android {
namespace base {
@@ -115,11 +118,84 @@
}
#endif
+static LogId log_id_tToLogId(int buffer_id) {
+ switch (buffer_id) {
+ case LOG_ID_MAIN:
+ return MAIN;
+ case LOG_ID_SYSTEM:
+ return SYSTEM;
+ case LOG_ID_RADIO:
+ return RADIO;
+ case LOG_ID_CRASH:
+ return CRASH;
+ case LOG_ID_DEFAULT:
+ default:
+ return DEFAULT;
+ }
+}
+
+static int LogIdTolog_id_t(LogId log_id) {
+ switch (log_id) {
+ case MAIN:
+ return LOG_ID_MAIN;
+ case SYSTEM:
+ return LOG_ID_SYSTEM;
+ case RADIO:
+ return LOG_ID_RADIO;
+ case CRASH:
+ return LOG_ID_CRASH;
+ case DEFAULT:
+ default:
+ return LOG_ID_DEFAULT;
+ }
+}
+
+static LogSeverity PriorityToLogSeverity(int priority) {
+ switch (priority) {
+ case ANDROID_LOG_DEFAULT:
+ return INFO;
+ case ANDROID_LOG_VERBOSE:
+ return VERBOSE;
+ case ANDROID_LOG_DEBUG:
+ return DEBUG;
+ case ANDROID_LOG_INFO:
+ return INFO;
+ case ANDROID_LOG_WARN:
+ return WARNING;
+ case ANDROID_LOG_ERROR:
+ return ERROR;
+ case ANDROID_LOG_FATAL:
+ return FATAL;
+ default:
+ return FATAL;
+ }
+}
+
+static android_LogPriority LogSeverityToPriority(LogSeverity severity) {
+ switch (severity) {
+ case VERBOSE:
+ return ANDROID_LOG_VERBOSE;
+ case DEBUG:
+ return ANDROID_LOG_DEBUG;
+ case INFO:
+ return ANDROID_LOG_INFO;
+ case WARNING:
+ return ANDROID_LOG_WARN;
+ case ERROR:
+ return ANDROID_LOG_ERROR;
+ case FATAL_WITHOUT_ABORT:
+ case FATAL:
+ default:
+ return ANDROID_LOG_FATAL;
+ }
+}
+
static std::mutex& LoggingLock() {
static auto& logging_lock = *new std::mutex();
return logging_lock;
}
+// Only used for Q fallback.
static LogFunction& Logger() {
#ifdef __ANDROID__
static auto& logger = *new LogFunction(LogdLogger());
@@ -129,6 +205,7 @@
return logger;
}
+// Only used for Q fallback.
static AbortFunction& Aborter() {
static auto& aborter = *new AbortFunction(DefaultAborter);
return aborter;
@@ -158,6 +235,8 @@
}
static bool gInitialized = false;
+
+// Only used for Q fallback.
static LogSeverity gMinimumLogSeverity = INFO;
#if defined(__linux__)
@@ -218,8 +297,13 @@
static_assert(arraysize(log_characters) - 1 == FATAL + 1,
"Mismatch in size of log_characters and values in LogSeverity");
char severity_char = log_characters[severity];
- fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n", tag ? tag : "nullptr", severity_char,
- timestamp, getpid(), GetThreadId(), file, line, message);
+ if (file != nullptr) {
+ fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n", tag ? tag : "nullptr", severity_char,
+ timestamp, getpid(), GetThreadId(), file, line, message);
+ } else {
+ fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n", tag ? tag : "nullptr", severity_char,
+ timestamp, getpid(), GetThreadId(), message);
+ }
}
void StdioLogger(LogId, LogSeverity severity, const char* /*tag*/, const char* /*file*/,
@@ -248,29 +332,25 @@
void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
const char* file, unsigned int line,
const char* message) {
- static constexpr android_LogPriority kLogSeverityToAndroidLogPriority[] = {
- ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
- ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
- ANDROID_LOG_FATAL,
- };
- static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
- "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity");
-
- int priority = kLogSeverityToAndroidLogPriority[severity];
+ android_LogPriority priority = LogSeverityToPriority(severity);
if (id == DEFAULT) {
id = default_log_id_;
}
- static constexpr log_id kLogIdToAndroidLogId[] = {
- LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
- };
- static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
- "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
- log_id lg_id = kLogIdToAndroidLogId[id];
+ int lg_id = LogIdTolog_id_t(id);
- if (priority == ANDROID_LOG_FATAL) {
- __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
- message);
+ char log_message[1024];
+ if (priority == ANDROID_LOG_FATAL && file != nullptr) {
+ snprintf(log_message, sizeof(log_message), "%s:%u] %s", file, line, message);
+ } else {
+ snprintf(log_message, sizeof(log_message), "%s", message);
+ }
+
+ static auto& liblog_functions = GetLibLogFunctions();
+ if (liblog_functions) {
+ __android_logger_data logger_data = {sizeof(__android_logger_data), lg_id, priority, tag,
+ static_cast<const char*>(nullptr), 0};
+ liblog_functions->__android_log_logd_logger(&logger_data, log_message);
} else {
__android_log_buf_print(lg_id, priority, tag, "%s", message);
}
@@ -305,27 +385,27 @@
if (spec.size() == 3 && StartsWith(spec, "*:")) {
switch (spec[2]) {
case 'v':
- gMinimumLogSeverity = VERBOSE;
+ SetMinimumLogSeverity(VERBOSE);
continue;
case 'd':
- gMinimumLogSeverity = DEBUG;
+ SetMinimumLogSeverity(DEBUG);
continue;
case 'i':
- gMinimumLogSeverity = INFO;
+ SetMinimumLogSeverity(INFO);
continue;
case 'w':
- gMinimumLogSeverity = WARNING;
+ SetMinimumLogSeverity(WARNING);
continue;
case 'e':
- gMinimumLogSeverity = ERROR;
+ SetMinimumLogSeverity(ERROR);
continue;
case 'f':
- gMinimumLogSeverity = FATAL_WITHOUT_ABORT;
+ SetMinimumLogSeverity(FATAL_WITHOUT_ABORT);
continue;
// liblog will even suppress FATAL if you say 's' for silent, but that's
// crazy!
case 's':
- gMinimumLogSeverity = FATAL_WITHOUT_ABORT;
+ SetMinimumLogSeverity(FATAL_WITHOUT_ABORT);
continue;
}
}
@@ -335,13 +415,46 @@
}
void SetLogger(LogFunction&& logger) {
- std::lock_guard<std::mutex> lock(LoggingLock());
- Logger() = std::move(logger);
+ static auto& liblog_functions = GetLibLogFunctions();
+ if (liblog_functions) {
+ // We need to atomically swap the old and new pointers since other threads may be logging.
+ // We know all threads will be using the new logger after __android_log_set_logger() returns,
+ // so we can delete it then.
+ // This leaks one std::function<> per instance of libbase if multiple copies of libbase within a
+ // single process call SetLogger(). That is the same cost as having a static
+ // std::function<>, which is the not-thread-safe alternative.
+ static std::atomic<LogFunction*> logger_function(nullptr);
+ auto* old_logger_function = logger_function.exchange(new LogFunction(logger));
+ liblog_functions->__android_log_set_logger([](const struct __android_logger_data* logger_data,
+ const char* message) {
+ auto log_id = log_id_tToLogId(logger_data->buffer_id);
+ auto severity = PriorityToLogSeverity(logger_data->priority);
+
+ auto& function = *logger_function.load(std::memory_order_acquire);
+ function(log_id, severity, logger_data->tag, logger_data->file, logger_data->line, message);
+ });
+ delete old_logger_function;
+ } else {
+ std::lock_guard<std::mutex> lock(LoggingLock());
+ Logger() = std::move(logger);
+ }
}
void SetAborter(AbortFunction&& aborter) {
- std::lock_guard<std::mutex> lock(LoggingLock());
- Aborter() = std::move(aborter);
+ static auto& liblog_functions = GetLibLogFunctions();
+ if (liblog_functions) {
+ // See the comment in SetLogger().
+ static std::atomic<AbortFunction*> abort_function(nullptr);
+ auto* old_abort_function = abort_function.exchange(new AbortFunction(aborter));
+ __android_log_set_aborter([](const char* abort_message) {
+ auto& function = *abort_function.load(std::memory_order_acquire);
+ function(abort_message);
+ });
+ delete old_abort_function;
+ } else {
+ std::lock_guard<std::mutex> lock(LoggingLock());
+ Aborter() = std::move(aborter);
+ }
}
// This indirection greatly reduces the stack impact of having lots of
@@ -444,7 +557,12 @@
// Abort if necessary.
if (data_->GetSeverity() == FATAL) {
- Aborter()(msg.c_str());
+ static auto& liblog_functions = GetLibLogFunctions();
+ if (liblog_functions) {
+ liblog_functions->__android_log_call_aborter(msg.c_str());
+ } else {
+ Aborter()(msg.c_str());
+ }
}
}
@@ -454,25 +572,65 @@
void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
const char* message) {
+ static auto& liblog_functions = GetLibLogFunctions();
+ auto priority = LogSeverityToPriority(severity);
if (tag == nullptr) {
std::lock_guard<std::recursive_mutex> lock(TagLock());
if (gDefaultTag == nullptr) {
gDefaultTag = new std::string(getprogname());
}
- Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message);
+
+ if (liblog_functions) {
+ __android_logger_data logger_data = {sizeof(__android_logger_data), LOG_ID_DEFAULT, priority,
+ gDefaultTag->c_str(), file, line};
+ __android_log_write_logger_data(&logger_data, message);
+ } else {
+ Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message);
+ }
} else {
- Logger()(DEFAULT, severity, tag, file, line, message);
+ if (liblog_functions) {
+ __android_logger_data logger_data = {
+ sizeof(__android_logger_data), LOG_ID_DEFAULT, priority, tag, file, line};
+ __android_log_write_logger_data(&logger_data, message);
+ } else {
+ Logger()(DEFAULT, severity, tag, file, line, message);
+ }
}
}
LogSeverity GetMinimumLogSeverity() {
+ static auto& liblog_functions = GetLibLogFunctions();
+ if (liblog_functions) {
+ return PriorityToLogSeverity(liblog_functions->__android_log_get_minimum_priority());
+ } else {
return gMinimumLogSeverity;
+ }
+}
+
+bool ShouldLog(LogSeverity severity, const char* tag) {
+ static auto& liblog_functions = GetLibLogFunctions();
+ // Even though we're not using the R liblog functions in this function, if we're running on Q,
+ // we need to fall back to using gMinimumLogSeverity, since __android_log_is_loggable() will not
+ // take into consideration the value from SetMinimumLogSeverity().
+ if (liblog_functions) {
+ // TODO: It is safe to pass nullptr for tag, but it will be better to use the default log tag.
+ int priority = LogSeverityToPriority(severity);
+ return __android_log_is_loggable(priority, tag, ANDROID_LOG_INFO);
+ } else {
+ return severity >= gMinimumLogSeverity;
+ }
}
LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
- LogSeverity old_severity = gMinimumLogSeverity;
- gMinimumLogSeverity = new_severity;
- return old_severity;
+ static auto& liblog_functions = GetLibLogFunctions();
+ if (liblog_functions) {
+ auto priority = LogSeverityToPriority(new_severity);
+ return PriorityToLogSeverity(liblog_functions->__android_log_set_minimum_priority(priority));
+ } else {
+ LogSeverity old_severity = gMinimumLogSeverity;
+ gMinimumLogSeverity = new_severity;
+ return old_severity;
+ }
}
ScopedLogSeverity::ScopedLogSeverity(LogSeverity new_severity) {
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 3113fb4..8f46196 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -140,10 +140,6 @@
CHECK_WOULD_LOG_ENABLED(FATAL);
}
-TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_disabled) {
- CHECK_WOULD_LOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_enabled) {
CHECK_WOULD_LOG_ENABLED(FATAL_WITHOUT_ABORT);
}
@@ -266,10 +262,6 @@
CheckMessage(cap2, android::base::severity, "foobar"); \
} \
-TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_disabled) {
- CHECK_LOG_STREAM_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_enabled) {
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(FATAL_WITHOUT_ABORT));
}
@@ -352,10 +344,6 @@
ASSERT_DEATH({SuppressAbortUI(); LOG(::android::base::FATAL) << "foobar";}, "foobar");
}
-TEST(logging, LOG_FATAL_WITHOUT_ABORT_disabled) {
- CHECK_LOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
TEST(logging, LOG_FATAL_WITHOUT_ABORT_enabled) {
ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(FATAL_WITHOUT_ABORT));
}
@@ -508,10 +496,6 @@
ASSERT_DEATH({SuppressAbortUI(); PLOG(::android::base::FATAL) << "foobar";}, "foobar");
}
-TEST(logging, PLOG_FATAL_WITHOUT_ABORT_disabled) {
- CHECK_PLOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
TEST(logging, PLOG_FATAL_WITHOUT_ABORT_enabled) {
ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(FATAL_WITHOUT_ABORT));
}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 6e01289..f8192b5 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -592,19 +592,20 @@
g_callbacks = *callbacks;
}
- void* thread_stack_allocation =
- mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ size_t thread_stack_pages = 8;
+ void* thread_stack_allocation = mmap(nullptr, PAGE_SIZE * (thread_stack_pages + 2), PROT_NONE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (thread_stack_allocation == MAP_FAILED) {
fatal_errno("failed to allocate debuggerd thread stack");
}
char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE;
- if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+ if (mprotect(stack, PAGE_SIZE * thread_stack_pages, PROT_READ | PROT_WRITE) != 0) {
fatal_errno("failed to mprotect debuggerd thread stack");
}
// Stack grows negatively, set it to the last byte in the page...
- stack = (stack + PAGE_SIZE - 1);
+ stack = (stack + thread_stack_pages * PAGE_SIZE - 1);
// and align it.
stack -= 15;
pseudothread_stack = stack;
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
index 5066046..9c80765 100644
--- a/fastboot/device/usb_client.cpp
+++ b/fastboot/device/usb_client.cpp
@@ -297,3 +297,7 @@
CloseFunctionFs(handle_.get());
return 0;
}
+
+int ClientUsbTransport::Reset() {
+ return 0;
+}
diff --git a/fastboot/device/usb_client.h b/fastboot/device/usb_client.h
index 3694f9a..e6a1a8b 100644
--- a/fastboot/device/usb_client.h
+++ b/fastboot/device/usb_client.h
@@ -29,6 +29,7 @@
ssize_t Read(void* data, size_t len) override;
ssize_t Write(const void* data, size_t len) override;
int Close() override;
+ int Reset() override;
private:
std::unique_ptr<usb_handle> handle_;
diff --git a/fastboot/fuzzy_fastboot/Android.bp b/fastboot/fuzzy_fastboot/Android.bp
index d48cfa9..bb54fd9 100644
--- a/fastboot/fuzzy_fastboot/Android.bp
+++ b/fastboot/fuzzy_fastboot/Android.bp
@@ -5,7 +5,7 @@
srcs: [
"main.cpp",
"extensions.cpp",
- "usb_transport_sniffer.cpp",
+ "transport_sniffer.cpp",
"fixtures.cpp",
"test_utils.cpp",
],
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index bc13a8c..bd76ff4 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -48,12 +48,13 @@
#include <gtest/gtest.h>
#include "fastboot_driver.h"
+#include "tcp.h"
#include "usb.h"
#include "extensions.h"
#include "fixtures.h"
#include "test_utils.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
using namespace std::literals::chrono_literals;
@@ -74,7 +75,14 @@
return 0;
}
+bool FastBootTest::IsFastbootOverTcp() {
+ // serial contains ":" is treated as host ip and port number
+ return (device_serial.find(":") != std::string::npos);
+}
+
bool FastBootTest::UsbStillAvailible() {
+ if (IsFastbootOverTcp()) return true;
+
// For some reason someone decided to prefix the path with "usb:"
std::string prefix("usb:");
if (std::equal(prefix.begin(), prefix.end(), device_path.begin())) {
@@ -113,15 +121,19 @@
ASSERT_TRUE(UsbStillAvailible()); // The device disconnected
}
- const auto matcher = [](usb_ifc_info* info) -> int {
- return MatchFastboot(info, device_serial);
- };
- for (int i = 0; i < MAX_USB_TRIES && !transport; i++) {
- std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
- if (usb)
- transport = std::unique_ptr<UsbTransportSniffer>(
- new UsbTransportSniffer(std::move(usb), serial_port));
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ if (IsFastbootOverTcp()) {
+ ConnectTcpFastbootDevice();
+ } else {
+ const auto matcher = [](usb_ifc_info* info) -> int {
+ return MatchFastboot(info, device_serial);
+ };
+ for (int i = 0; i < MAX_USB_TRIES && !transport; i++) {
+ std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
+ if (usb)
+ transport = std::unique_ptr<TransportSniffer>(
+ new TransportSniffer(std::move(usb), serial_port));
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
}
ASSERT_TRUE(transport); // no nullptr
@@ -154,6 +166,8 @@
// TODO, this should eventually be piped to a file instead of stdout
void FastBootTest::TearDownSerial() {
+ if (IsFastbootOverTcp()) return;
+
if (!transport) return;
// One last read from serial
transport->ProcessSerial();
@@ -167,9 +181,34 @@
}
}
+void FastBootTest::ConnectTcpFastbootDevice() {
+ std::size_t found = device_serial.find(":");
+ if (found != std::string::npos) {
+ for (int i = 0; i < MAX_TCP_TRIES && !transport; i++) {
+ std::string error;
+ std::unique_ptr<Transport> tcp(
+ tcp::Connect(device_serial.substr(0, found), tcp::kDefaultPort, &error)
+ .release());
+ if (tcp)
+ transport =
+ std::unique_ptr<TransportSniffer>(new TransportSniffer(std::move(tcp), 0));
+ if (transport != nullptr) break;
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+}
+
void FastBootTest::ReconnectFastbootDevice() {
fb.reset();
transport.reset();
+
+ if (IsFastbootOverTcp()) {
+ ConnectTcpFastbootDevice();
+ device_path = cb_scratch;
+ fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+ return;
+ }
+
while (UsbStillAvailible())
;
printf("WAITING FOR DEVICE\n");
@@ -180,8 +219,8 @@
while (!transport) {
std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
if (usb) {
- transport = std::unique_ptr<UsbTransportSniffer>(
- new UsbTransportSniffer(std::move(usb), serial_port));
+ transport = std::unique_ptr<TransportSniffer>(
+ new TransportSniffer(std::move(usb), serial_port));
}
std::this_thread::sleep_for(1s);
}
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index c71c897..2468868 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -31,7 +31,7 @@
#include "fastboot_driver.h"
#include "extensions.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
namespace fastboot {
@@ -45,11 +45,14 @@
static int serial_port;
static std::string device_serial;
static constexpr int MAX_USB_TRIES = 10;
+ static constexpr int MAX_TCP_TRIES = 6000;
static int MatchFastboot(usb_ifc_info* info, const std::string& local_serial = "");
+ static bool IsFastbootOverTcp();
bool UsbStillAvailible();
bool UserSpaceFastboot();
void ReconnectFastbootDevice();
+ void ConnectTcpFastbootDevice();
protected:
RetCode DownloadCommand(uint32_t size, std::string* response = nullptr,
@@ -64,7 +67,7 @@
void TearDownSerial();
void SetLockState(bool unlock, bool assert_change = true);
- std::unique_ptr<UsbTransportSniffer> transport;
+ std::unique_ptr<TransportSniffer> transport;
std::unique_ptr<FastBootDriver> fb;
private:
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index a1d69d2..b9784fe 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -54,7 +54,7 @@
#include "extensions.h"
#include "fixtures.h"
#include "test_utils.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
namespace fastboot {
@@ -1756,16 +1756,19 @@
}
setbuf(stdout, NULL); // no buffering
- printf("<Waiting for Device>\n");
- const auto matcher = [](usb_ifc_info* info) -> int {
- return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
- };
- Transport* transport = nullptr;
- while (!transport) {
- transport = usb_open(matcher);
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
+
+ if (!fastboot::FastBootTest::IsFastbootOverTcp()) {
+ printf("<Waiting for Device>\n");
+ const auto matcher = [](usb_ifc_info* info) -> int {
+ return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
+ };
+ Transport* transport = nullptr;
+ while (!transport) {
+ transport = usb_open(matcher);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ transport->Close();
}
- transport->Close();
if (args.find("serial_port") != args.end()) {
fastboot::FastBootTest::serial_port = fastboot::ConfigureSerial(args.at("serial_port"));
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp b/fastboot/fuzzy_fastboot/transport_sniffer.cpp
similarity index 91%
rename from fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
rename to fastboot/fuzzy_fastboot/transport_sniffer.cpp
index 7c595f4..b55ffd3 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
+++ b/fastboot/fuzzy_fastboot/transport_sniffer.cpp
@@ -1,4 +1,4 @@
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
#include <android-base/stringprintf.h>
#include <sys/select.h>
#include <sys/time.h>
@@ -8,15 +8,15 @@
namespace fastboot {
-UsbTransportSniffer::UsbTransportSniffer(std::unique_ptr<UsbTransport> transport,
+TransportSniffer::TransportSniffer(std::unique_ptr<Transport> transport,
const int serial_fd)
: transport_(std::move(transport)), serial_fd_(serial_fd) {}
-UsbTransportSniffer::~UsbTransportSniffer() {
+TransportSniffer::~TransportSniffer() {
Close();
}
-ssize_t UsbTransportSniffer::Read(void* data, size_t len) {
+ssize_t TransportSniffer::Read(void* data, size_t len) {
ProcessSerial();
ssize_t ret = transport_->Read(data, len);
@@ -37,7 +37,7 @@
return ret;
}
-ssize_t UsbTransportSniffer::Write(const void* data, size_t len) {
+ssize_t TransportSniffer::Write(const void* data, size_t len) {
ProcessSerial();
size_t ret = transport_->Write(data, len);
@@ -58,11 +58,11 @@
return ret;
}
-int UsbTransportSniffer::Close() {
+int TransportSniffer::Close() {
return transport_->Close();
}
-int UsbTransportSniffer::Reset() {
+int TransportSniffer::Reset() {
ProcessSerial();
int ret = transport_->Reset();
std::vector<char> buf;
@@ -72,7 +72,7 @@
return ret;
}
-const std::vector<UsbTransportSniffer::Event> UsbTransportSniffer::Transfers() {
+const std::vector<TransportSniffer::Event> TransportSniffer::Transfers() {
return transfers_;
}
@@ -81,7 +81,7 @@
* the failure. This method will look through its log of captured events, and
* create a clean printable string of everything that happened.
*/
-std::string UsbTransportSniffer::CreateTrace() {
+std::string TransportSniffer::CreateTrace() {
std::string ret;
const auto no_print = [](char c) -> bool { return !isprint(c); };
@@ -158,7 +158,7 @@
// This is a quick call to flush any UART logs the device might have sent
// to our internal event log. It will wait up to 10ms for data to appear
-void UsbTransportSniffer::ProcessSerial() {
+void TransportSniffer::ProcessSerial() {
if (serial_fd_ <= 0) return;
fd_set set;
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h b/fastboot/fuzzy_fastboot/transport_sniffer.h
similarity index 90%
rename from fastboot/fuzzy_fastboot/usb_transport_sniffer.h
rename to fastboot/fuzzy_fastboot/transport_sniffer.h
index 8119aea..2cbb9fe 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
+++ b/fastboot/fuzzy_fastboot/transport_sniffer.h
@@ -42,12 +42,12 @@
/* A special class for sniffing reads and writes
*
* A useful debugging tool is to see the raw fastboot transactions going between
- * the host and device. This class wraps the UsbTransport class, and snoops and saves
+ * the host and device. This class is a special subclass of Transport that snoops and saves
* all the transactions going on. Additionally, if there is a console serial port
* from the device, this class can monitor it as well and capture the interleaving of
* transport transactions and UART log messages.
*/
-class UsbTransportSniffer : public UsbTransport {
+class TransportSniffer : public Transport {
public:
enum EventType {
READ,
@@ -67,8 +67,8 @@
const std::vector<char> buf;
};
- UsbTransportSniffer(std::unique_ptr<UsbTransport> transport, const int serial_fd = 0);
- ~UsbTransportSniffer() override;
+ TransportSniffer(std::unique_ptr<Transport> transport, const int serial_fd = 0);
+ ~TransportSniffer() override;
virtual ssize_t Read(void* data, size_t len) override;
virtual ssize_t Write(const void* data, size_t len) override;
@@ -81,7 +81,7 @@
private:
std::vector<Event> transfers_;
- std::unique_ptr<UsbTransport> transport_;
+ std::unique_ptr<Transport> transport_;
const int serial_fd_;
};
diff --git a/fastboot/tcp.cpp b/fastboot/tcp.cpp
index dd6fbf8..dca306f 100644
--- a/fastboot/tcp.cpp
+++ b/fastboot/tcp.cpp
@@ -64,6 +64,7 @@
ssize_t Read(void* data, size_t length) override;
ssize_t Write(const void* data, size_t length) override;
int Close() override;
+ int Reset() override;
private:
explicit TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
@@ -178,6 +179,10 @@
return result;
}
+int TcpTransport::Reset() {
+ return 0;
+}
+
std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error) {
return internal::Connect(Socket::NewClient(Socket::Protocol::kTcp, hostname, port, error),
error);
diff --git a/fastboot/transport.h b/fastboot/transport.h
index 96b90d2..de0cc92 100644
--- a/fastboot/transport.h
+++ b/fastboot/transport.h
@@ -36,6 +36,8 @@
// Closes the underlying transport. Returns 0 on success.
virtual int Close() = 0;
+ virtual int Reset() = 0;
+
// Blocks until the transport disconnects. Transports that don't support
// this will return immediately. Returns 0 on success.
virtual int WaitForDisconnect() { return 0; }
diff --git a/fastboot/udp.cpp b/fastboot/udp.cpp
index 53fb347..308c96c 100644
--- a/fastboot/udp.cpp
+++ b/fastboot/udp.cpp
@@ -109,6 +109,7 @@
ssize_t Read(void* data, size_t length) override;
ssize_t Write(const void* data, size_t length) override;
int Close() override;
+ int Reset() override;
private:
explicit UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
@@ -370,6 +371,10 @@
return result;
}
+int UdpTransport::Reset() {
+ return 0;
+}
+
std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error) {
return internal::Connect(Socket::NewClient(Socket::Protocol::kUdp, hostname, port, error),
error);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 03c7943..ed82066 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1092,7 +1092,9 @@
return FS_MGR_MNTALL_FAIL;
}
- for (size_t i = 0; i < fstab->size(); i++) {
+ // Keep i int to prevent unsigned integer overflow from (i = top_idx - 1),
+ // where top_idx is 0. It will give SIGABRT
+ for (int i = 0; i < static_cast<int>(fstab->size()); i++) {
auto& current_entry = (*fstab)[i];
// If a filesystem should have been mounted in the first stage, we
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 9e67c66..c67e33d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -75,6 +75,7 @@
"snapshot.cpp",
"snapshot_metadata_updater.cpp",
"partition_cow_creator.cpp",
+ "return.cpp",
"utility.cpp",
],
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/return.h b/fs_mgr/libsnapshot/include/libsnapshot/return.h
new file mode 100644
index 0000000..1f132fa
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/return.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2019 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.
+
+#pragma once
+
+#include <stdint.h>
+#include <string.h>
+
+#include <libfiemap/fiemap_status.h>
+
+namespace android::snapshot {
+
+// SnapshotManager functions return either bool or Return objects. "Return" types provides
+// more information about the reason of the failure.
+class Return {
+ using FiemapStatus = android::fiemap::FiemapStatus;
+
+ public:
+ enum class ErrorCode : int32_t {
+ SUCCESS = static_cast<int32_t>(FiemapStatus::ErrorCode::SUCCESS),
+ ERROR = static_cast<int32_t>(FiemapStatus::ErrorCode::ERROR),
+ NEEDS_REBOOT = ERROR + 1,
+ NO_SPACE = static_cast<int32_t>(FiemapStatus::ErrorCode::NO_SPACE),
+ };
+ ErrorCode error_code() const { return error_code_; }
+ bool is_ok() const { return error_code() == ErrorCode::SUCCESS; }
+ operator bool() const { return is_ok(); }
+ // Total required size on /userdata.
+ uint64_t required_size() const { return required_size_; }
+ std::string string() const;
+
+ static Return Ok() { return Return(ErrorCode::SUCCESS); }
+ static Return Error() { return Return(ErrorCode::ERROR); }
+ static Return NoSpace(uint64_t size) { return Return(ErrorCode::NO_SPACE, size); }
+ static Return NeedsReboot() { return Return(ErrorCode::NEEDS_REBOOT); }
+ // Does not set required_size_ properly even when status.error_code() == NO_SPACE.
+ explicit Return(const FiemapStatus& status)
+ : error_code_(FromFiemapStatusErrorCode(status.error_code())), required_size_(0) {}
+
+ private:
+ ErrorCode error_code_;
+ uint64_t required_size_;
+ Return(ErrorCode error_code, uint64_t required_size = 0)
+ : error_code_(error_code), required_size_(required_size) {}
+
+ // FiemapStatus::ErrorCode -> ErrorCode
+ static ErrorCode FromFiemapStatusErrorCode(FiemapStatus::ErrorCode error_code);
+};
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 61946f7..959d8a7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -35,6 +35,7 @@
#include <update_engine/update_metadata.pb.h>
#include <libsnapshot/auto_device.h>
+#include <libsnapshot/return.h>
#ifndef FRIEND_TEST
#define FRIEND_TEST(test_set_name, individual_test) \
@@ -91,27 +92,6 @@
using FiemapStatus = android::fiemap::FiemapStatus;
public:
- // SnapshotManager functions return either bool or Return objects. "Return" types provides
- // more information about the reason of the failure.
- class Return : public FiemapStatus {
- public:
- // Total required size on /userdata.
- uint64_t required_size() const { return required_size_; }
-
- static Return Ok() { return Return(FiemapStatus::ErrorCode::SUCCESS); }
- static Return Error() { return Return(FiemapStatus::ErrorCode::ERROR); }
- static Return NoSpace(uint64_t size) {
- return Return(FiemapStatus::ErrorCode::NO_SPACE, size);
- }
- // Does not set required_size_ properly even when status.error_code() == NO_SPACE.
- explicit Return(const FiemapStatus& status) : Return(status.error_code()) {}
-
- private:
- uint64_t required_size_;
- Return(FiemapStatus::ErrorCode code, uint64_t required_size = 0)
- : FiemapStatus(code), required_size_(required_size) {}
- };
-
// Dependency injection for testing.
class IDeviceInfo {
public:
@@ -201,9 +181,11 @@
// Wait for the merge if rebooted into the new slot. Does NOT initiate a
// merge. If the merge has not been initiated (but should be), wait.
// Returns:
- // - true there is no merge or merge finishes
- // - false indicating an error has occurred
- bool WaitForMerge();
+ // - Return::Ok(): there is no merge or merge finishes
+ // - Return::NeedsReboot(): merge finishes but need a reboot before
+ // applying the next update.
+ // - Return::Error(): other irrecoverable errors
+ Return WaitForMerge();
// Find the status of the current update, if any.
//
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 11de6ed..98bf56a 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -42,7 +42,6 @@
using testing::_;
using testing::AssertionResult;
using testing::NiceMock;
-using testing::Return;
using namespace android::storage_literals;
using namespace std::string_literals;
@@ -117,6 +116,7 @@
class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
public:
SnapshotTestPropertyFetcher(const std::string& slot_suffix) {
+ using testing::Return;
ON_CALL(*this, GetProperty("ro.boot.slot_suffix", _)).WillByDefault(Return(slot_suffix));
ON_CALL(*this, GetBoolProperty("ro.boot.dynamic_partitions", _))
.WillByDefault(Return(true));
diff --git a/fs_mgr/libsnapshot/return.cpp b/fs_mgr/libsnapshot/return.cpp
new file mode 100644
index 0000000..6559c12
--- /dev/null
+++ b/fs_mgr/libsnapshot/return.cpp
@@ -0,0 +1,46 @@
+// Copyright (C) 2019 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 <libsnapshot/return.h>
+
+#include <string.h>
+
+using android::fiemap::FiemapStatus;
+
+namespace android::snapshot {
+
+std::string Return::string() const {
+ switch (error_code()) {
+ case ErrorCode::ERROR:
+ return "Error";
+ case ErrorCode::NEEDS_REBOOT:
+ return "Retry after reboot";
+ case ErrorCode::SUCCESS:
+ [[fallthrough]];
+ case ErrorCode::NO_SPACE:
+ return strerror(-static_cast<int>(error_code()));
+ }
+}
+
+Return::ErrorCode Return::FromFiemapStatusErrorCode(FiemapStatus::ErrorCode error_code) {
+ switch (error_code) {
+ case FiemapStatus::ErrorCode::SUCCESS:
+ case FiemapStatus::ErrorCode::ERROR:
+ case FiemapStatus::ErrorCode::NO_SPACE:
+ return static_cast<ErrorCode>(error_code);
+ default:
+ return ErrorCode::ERROR;
+ }
+}
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 70a69a5..912087c 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -290,7 +290,7 @@
return true;
}
-SnapshotManager::Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
+Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
CHECK(lock);
CHECK(lock->lock_mode() == LOCK_EX);
if (!EnsureImageManager()) return Return::Error();
@@ -1249,15 +1249,45 @@
return UpdateState::None;
}
- auto state = ReadUpdateState(lock.get());
- if (progress) {
- *progress = 0.0;
- if (state == UpdateState::Merging) {
- // :TODO: When merging is implemented, set progress_val.
- } else if (state == UpdateState::MergeCompleted) {
- *progress = 100.0;
- }
+ SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get());
+ auto state = update_status.state();
+ if (progress == nullptr) {
+ return state;
}
+
+ if (state == UpdateState::MergeCompleted) {
+ *progress = 100.0;
+ return state;
+ }
+
+ *progress = 0.0;
+ if (state != UpdateState::Merging) {
+ return state;
+ }
+
+ // Sum all the snapshot states as if the system consists of a single huge
+ // snapshots device, then compute the merge completion percentage of that
+ // device.
+ std::vector<std::string> snapshots;
+ if (!ListSnapshots(lock.get(), &snapshots)) {
+ LOG(ERROR) << "Could not list snapshots";
+ return state;
+ }
+
+ DmTargetSnapshot::Status fake_snapshots_status = {};
+ for (const auto& snapshot : snapshots) {
+ DmTargetSnapshot::Status current_status;
+
+ if (!QuerySnapshotStatus(snapshot, nullptr, ¤t_status)) continue;
+
+ fake_snapshots_status.sectors_allocated += current_status.sectors_allocated;
+ fake_snapshots_status.total_sectors += current_status.total_sectors;
+ fake_snapshots_status.metadata_sectors += current_status.metadata_sectors;
+ }
+
+ *progress = DmTargetSnapshot::MergePercent(fake_snapshots_status,
+ update_status.sectors_allocated());
+
return state;
}
@@ -1890,21 +1920,19 @@
}
}
-static SnapshotManager::Return AddRequiredSpace(
- SnapshotManager::Return orig,
- const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
- if (orig.error_code() != SnapshotManager::Return::ErrorCode::NO_SPACE) {
+static Return AddRequiredSpace(Return orig,
+ const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
+ if (orig.error_code() != Return::ErrorCode::NO_SPACE) {
return orig;
}
uint64_t sum = 0;
for (auto&& [name, status] : all_snapshot_status) {
sum += status.cow_file_size();
}
- return SnapshotManager::Return::NoSpace(sum);
+ return Return::NoSpace(sum);
}
-SnapshotManager::Return SnapshotManager::CreateUpdateSnapshots(
- const DeltaArchiveManifest& manifest) {
+Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) {
auto lock = LockExclusive();
if (!lock) return Return::Error();
@@ -1998,7 +2026,7 @@
return Return::Ok();
}
-SnapshotManager::Return SnapshotManager::CreateUpdateSnapshotsInternal(
+Return SnapshotManager::CreateUpdateSnapshotsInternal(
LockedFile* lock, const DeltaArchiveManifest& manifest, PartitionCowCreator* cow_creator,
AutoDeviceList* created_devices,
std::map<std::string, SnapshotStatus>* all_snapshot_status) {
@@ -2131,7 +2159,7 @@
return Return::Ok();
}
-SnapshotManager::Return SnapshotManager::InitializeUpdateSnapshots(
+Return SnapshotManager::InitializeUpdateSnapshots(
LockedFile* lock, MetadataBuilder* target_metadata,
const LpMetadata* exported_target_metadata, const std::string& target_suffix,
const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
@@ -2286,9 +2314,19 @@
}
}
+ unsigned int last_progress = 0;
+ auto callback = [&]() -> void {
+ double progress;
+ GetUpdateState(&progress);
+ if (last_progress < static_cast<unsigned int>(progress)) {
+ last_progress = progress;
+ LOG(INFO) << "Waiting for merge to complete: " << last_progress << "%.";
+ }
+ };
+
LOG(INFO) << "Waiting for any previous merge request to complete. "
<< "This can take up to several minutes.";
- auto state = ProcessUpdateState();
+ auto state = ProcessUpdateState(callback);
if (state == UpdateState::None) {
LOG(INFO) << "Can't find any snapshot to merge.";
return state;
@@ -2300,14 +2338,15 @@
}
// All other states can be handled by ProcessUpdateState.
LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
- state = ProcessUpdateState();
+ last_progress = 0;
+ state = ProcessUpdateState(callback);
}
LOG(INFO) << "Merge finished with state \"" << state << "\".";
return state;
}
-bool SnapshotManager::WaitForMerge() {
+Return SnapshotManager::WaitForMerge() {
LOG(INFO) << "Waiting for any previous merge request to complete. "
<< "This can take up to several minutes.";
while (true) {
@@ -2318,7 +2357,18 @@
continue;
}
LOG(INFO) << "Wait for merge exits with state " << state;
- return state == UpdateState::None || state == UpdateState::MergeCompleted;
+ switch (state) {
+ case UpdateState::None:
+ [[fallthrough]];
+ case UpdateState::MergeCompleted:
+ [[fallthrough]];
+ case UpdateState::Cancelled:
+ return Return::Ok();
+ case UpdateState::MergeNeedsReboot:
+ return Return::NeedsReboot();
+ default:
+ return Return::Error();
+ }
}
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index cea9d69..47ac474 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1604,7 +1604,7 @@
ASSERT_TRUE(sm->BeginUpdate());
auto res = sm->CreateUpdateSnapshots(manifest_);
ASSERT_FALSE(res);
- ASSERT_EQ(SnapshotManager::Return::ErrorCode::NO_SPACE, res.error_code());
+ ASSERT_EQ(Return::ErrorCode::NO_SPACE, res.error_code());
ASSERT_GE(res.required_size(), 14_MiB);
ASSERT_LT(res.required_size(), 15_MiB);
}
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index f01500f..3a64448 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -86,9 +86,7 @@
}
}
-SnapshotManager::Return InitializeCow(const std::string& device) {
- using Return = SnapshotManager::Return;
-
+Return InitializeCow(const std::string& device) {
// When the kernel creates a persistent dm-snapshot, it requires a CoW file
// to store the modifications. The kernel interface does not specify how
// the CoW is used, and there is no standard associated.
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 0453256..ad46090 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -111,7 +111,7 @@
android::fs_mgr::MetadataBuilder* builder, const std::string& suffix);
// Initialize a device before using it as the COW device for a dm-snapshot device.
-SnapshotManager::Return InitializeCow(const std::string& device);
+Return InitializeCow(const std::string& device);
// "Atomically" write string to file. This is done by a series of actions:
// 1. Write to path + ".tmp"
diff --git a/init/init.cpp b/init/init.cpp
index 5f97e44..a25bf6c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -730,8 +730,8 @@
}
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
-
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
+ am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
am.QueueEventTrigger("early-init");
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
diff --git a/init/security.cpp b/init/security.cpp
index 586d0c7..6cbe642 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -18,14 +18,19 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/perf_event.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
#include <unistd.h>
#include <fstream>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/unique_fd.h>
using android::base::unique_fd;
+using android::base::SetProperty;
namespace android {
namespace init {
@@ -197,5 +202,61 @@
return {};
}
+// Test for whether the kernel has SELinux hooks for the perf_event_open()
+// syscall. If the hooks are present, we can stop using the other permission
+// mechanism (perf_event_paranoid sysctl), and use only the SELinux policy to
+// control access to the syscall. The hooks are expected on all Android R
+// release kernels, but might be absent on devices that upgrade while keeping an
+// older kernel.
+//
+// There is no direct/synchronous way of finding out that a syscall failed due
+// to SELinux. Therefore we test for a combination of a success and a failure
+// that are explained by the platform's SELinux policy for the "init" domain:
+// * cpu-scoped perf_event is allowed
+// * ioctl() on the event fd is disallowed with EACCES
+//
+// Since init has CAP_SYS_ADMIN, these tests are not affected by the system-wide
+// perf_event_paranoid sysctl.
+//
+// If the SELinux hooks are detected, a special sysprop
+// (sys.init.perf_lsm_hooks) is set, which translates to a modification of
+// perf_event_paranoid (through init.rc sysprop actions).
+//
+// TODO(b/137092007): this entire test can be removed once the platform stops
+// supporting kernels that precede the perf_event_open hooks (Android common
+// kernels 4.4 and 4.9).
+Result<void> TestPerfEventSelinuxAction(const BuiltinArguments&) {
+ // Use a trivial event that will be configured, but not started.
+ struct perf_event_attr pe = {
+ .type = PERF_TYPE_SOFTWARE,
+ .size = sizeof(struct perf_event_attr),
+ .config = PERF_COUNT_SW_TASK_CLOCK,
+ .disabled = 1,
+ .exclude_kernel = 1,
+ };
+
+ // Open the above event targeting cpu 0. (EINTR not possible.)
+ unique_fd fd(static_cast<int>(syscall(__NR_perf_event_open, &pe, /*pid=*/-1,
+ /*cpu=*/0,
+ /*group_fd=*/-1, /*flags=*/0)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Unexpected perf_event_open error";
+ return {};
+ }
+
+ int ioctl_ret = ioctl(fd, PERF_EVENT_IOC_RESET);
+ if (ioctl_ret != -1) {
+ // Success implies that the kernel doesn't have the hooks.
+ return {};
+ } else if (errno != EACCES) {
+ PLOG(ERROR) << "Unexpected perf_event ioctl error";
+ return {};
+ }
+
+ // Conclude that the SELinux hooks are present.
+ SetProperty("sys.init.perf_lsm_hooks", "1");
+ return {};
+}
+
} // namespace init
} // namespace android
diff --git a/init/security.h b/init/security.h
index b081a05..43c2739 100644
--- a/init/security.h
+++ b/init/security.h
@@ -29,6 +29,7 @@
Result<void> MixHwrngIntoLinuxRngAction(const BuiltinArguments&);
Result<void> SetMmapRndBitsAction(const BuiltinArguments&);
Result<void> SetKptrRestrictAction(const BuiltinArguments&);
+Result<void> TestPerfEventSelinuxAction(const BuiltinArguments&);
} // namespace init
} // namespace android
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index 2582cea..f1147dc 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -517,13 +517,16 @@
}
int __android_log_is_loggable(int prio, const char*, int def) {
- int logLevel = def;
- return logLevel >= 0 && prio >= logLevel;
+ int minimum_priority = __android_log_get_minimum_priority();
+ if (minimum_priority == ANDROID_LOG_DEFAULT) {
+ return prio >= def;
+ } else {
+ return prio >= minimum_priority;
+ }
}
int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
- int logLevel = def;
- return logLevel >= 0 && prio >= logLevel;
+ return __android_log_is_loggable(prio, nullptr, def);
}
int __android_log_is_debuggable() {
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 7290789..6530704 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -55,6 +55,7 @@
*/
#include <stdarg.h>
+#include <stddef.h>
#ifdef __cplusplus
extern "C" {
@@ -152,6 +153,12 @@
} log_id_t;
/**
+ * Let the logging function choose the best log target.
+ * This is not part of the enum since adding either -1 or 0xFFFFFFFF forces the enum to be signed or
+ * unsigned, which breaks unfortunately common arithmetic against LOG_ID_MIN and LOG_ID_MAX. */
+#define LOG_ID_DEFAULT -1
+
+/**
* Writes the constant string `text` to the log buffer `id`,
* with priority `prio` and tag `tag`.
*
@@ -170,6 +177,101 @@
int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
__attribute__((__format__(printf, 4, 5)));
+/**
+ * Logger data struct used for writing log messages to liblog via __android_log_write_logger_data()
+ * and sending log messages to user defined loggers specified in __android_log_set_logger().
+ */
+struct __android_logger_data {
+ size_t struct_size; /* Must be set to sizeof(__android_logger_data) and is used for versioning. */
+ int buffer_id; /* log_id_t or -1 to represent 'default'. */
+ int priority; /* android_LogPriority values. */
+ const char* tag;
+ const char* file; /* Optional file name, may be set to nullptr. */
+ unsigned int line; /* Optional line number, ignore if file is nullptr. */
+};
+
+/**
+ * Writes the log message specified with logger_data and msg to the log. logger_data includes
+ * additional file name and line number information that a logger may use. logger_data is versioned
+ * for backwards compatibility.
+ */
+void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg);
+
+/**
+ * Prototype for the 'logger' function that is called for every log message.
+ */
+typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
+ const char* message);
+
+/**
+ * Sets a user defined logger function. All log messages sent to liblog will be set to the
+ * function pointer specified by logger for processing.
+ */
+void __android_log_set_logger(__android_logger_function logger);
+
+/**
+ * Writes the log message to logd. This is an __android_logger_function and can be provided to
+ * __android_log_set_logger(). It is the default logger when running liblog on a device.
+ */
+void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg);
+
+/**
+ * Writes the log message to stderr. This is an __android_logger_function and can be provided to
+ * __android_log_set_logger(). It is the default logger when running liblog on host.
+ */
+void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
+ const char* message);
+
+/**
+ * Prototype for the 'abort' function that is called when liblog will abort due to
+ * __android_log_assert() failures.
+ */
+typedef void (*__android_aborter_function)(const char* abort_message);
+
+/**
+ * Sets a user defined aborter function that is called for __android_log_assert() failures.
+ */
+void __android_log_set_aborter(__android_aborter_function aborter);
+
+/**
+ * Calls the stored aborter function. This allows for other logging libraries to use the same
+ * aborter function by calling this function in liblog.
+ */
+void __android_log_call_aborter(const char* abort_message);
+
+/**
+ * Sets android_set_abort_message() on device then aborts(). This is the default aborter.
+ */
+void __android_log_default_aborter(const char* abort_message);
+
+/**
+ * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
+ * __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
+ * be printed. A non-zero result indicates yes, zero indicates false.
+ *
+ * If both a priority for a tag and a minimum priority are set by
+ * __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
+ * minimum priority needed to log. If only one is set, then that value is used to determine the
+ * minimum priority needed. If none are set, then default_priority is used.
+ *
+ * prio is ANDROID_LOG_VERBOSE to ANDROID_LOG_FATAL.
+ */
+int __android_log_is_loggable(int prio, const char* tag, int default_prio);
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
+
+/**
+ * Sets the minimum priority that will be logged for this process.
+ *
+ * This returns the previous set minimum priority, or ANDROID_LOG_DEFAULT if none was set.
+ */
+int __android_log_set_minimum_priority(int priority);
+
+/**
+ * Gets the minimum priority that will be logged for this process. If none has been set by a
+ * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
+ */
+int __android_log_get_minimum_priority();
+
#ifdef __cplusplus
}
#endif
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 65194ce..62b9805 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -67,7 +67,16 @@
LIGLOG_R { # introduced=30
global:
+ __android_log_call_aborter;
+ __android_log_default_aborter;
+ __android_log_get_minimum_priority;
+ __android_log_logd_logger;
__android_log_security_bswrite; # apex
+ __android_log_set_aborter;
+ __android_log_set_logger;
+ __android_log_set_minimum_priority;
+ __android_log_stderr_logger;
+ __android_log_write_logger_data;
};
LIBLOG_PRIVATE {
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index d6ef951..61b6fce 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -15,6 +15,7 @@
*/
#include <errno.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
@@ -23,11 +24,15 @@
#include <android/set_abort_message.h>
#endif
+#include <shared_mutex>
+
#include <android-base/macros.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+#include "android/log.h"
#include "logger.h"
+#include "rwlock.h"
#include "uio.h"
#if (FAKE_LOG_DEVICE == 0)
@@ -37,6 +42,14 @@
#include "fake_log_device.h"
#endif
+#if defined(__APPLE__)
+#include <pthread.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
#define LOG_BUF_SIZE 1024
#if defined(__ANDROID__)
@@ -93,6 +106,52 @@
#endif
}
+static int minimum_log_priority = ANDROID_LOG_DEFAULT;
+int __android_log_set_minimum_priority(int priority) {
+ int old_minimum_log_priority = minimum_log_priority;
+ minimum_log_priority = priority;
+ return old_minimum_log_priority;
+}
+
+int __android_log_get_minimum_priority() {
+ return minimum_log_priority;
+}
+
+#ifdef __ANDROID__
+static __android_logger_function logger_function = __android_log_logd_logger;
+#else
+static __android_logger_function logger_function = __android_log_stderr_logger;
+#endif
+static RwLock logger_function_lock;
+
+void __android_log_set_logger(__android_logger_function logger) {
+ auto lock = std::unique_lock{logger_function_lock};
+ logger_function = logger;
+}
+
+void __android_log_default_aborter(const char* abort_message) {
+#ifdef __ANDROID__
+ android_set_abort_message(abort_message);
+#else
+ UNUSED(abort_message);
+#endif
+ abort();
+}
+
+static __android_aborter_function aborter_function = __android_log_default_aborter;
+static RwLock aborter_function_lock;
+
+void __android_log_set_aborter(__android_aborter_function aborter) {
+ auto lock = std::unique_lock{aborter_function_lock};
+ aborter_function = aborter;
+}
+
+void __android_log_call_aborter(const char* abort_message) {
+ auto lock = std::shared_lock{aborter_function_lock};
+ aborter_function(abort_message);
+}
+
+#ifdef __ANDROID__
static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
int ret, save_errno;
struct timespec ts;
@@ -103,7 +162,6 @@
return -EINVAL;
}
-#if defined(__ANDROID__)
clock_gettime(android_log_clockid(), &ts);
if (log_id == LOG_ID_SECURITY) {
@@ -137,51 +195,106 @@
return -EPERM;
}
}
-#else
- /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- ts.tv_sec = tv.tv_sec;
- ts.tv_nsec = tv.tv_usec * 1000;
- }
-#endif
- ret = 0;
-
-#if (FAKE_LOG_DEVICE == 0)
ret = LogdWrite(log_id, &ts, vec, nr);
PmsgWrite(log_id, &ts, vec, nr);
-#else
- ret = FakeWrite(log_id, &ts, vec, nr);
-#endif
errno = save_errno;
return ret;
}
+#else
+static int write_to_log(log_id_t, struct iovec*, size_t) {
+ // Non-Android text logs should go to __android_log_stderr_logger, not here.
+ // Non-Android binary logs are always dropped.
+ return 1;
+}
+#endif
+
+// Copied from base/threads.cpp
+static uint64_t GetThreadId() {
+#if defined(__BIONIC__)
+ return gettid();
+#elif defined(__APPLE__)
+ uint64_t tid;
+ pthread_threadid_np(NULL, &tid);
+ return tid;
+#elif defined(__linux__)
+ return syscall(__NR_gettid);
+#elif defined(_WIN32)
+ return GetCurrentThreadId();
+#endif
+}
+
+void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
+ const char* message) {
+ struct tm now;
+ time_t t = time(nullptr);
+
+#if defined(_WIN32)
+ localtime_s(&now, &t);
+#else
+ localtime_r(&t, &now);
+#endif
+
+ char timestamp[32];
+ strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
+
+ static const char log_characters[] = "XXVDIWEF";
+ static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
+ "Mismatch in size of log_characters and values in android_LogPriority");
+ int priority =
+ logger_data->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : logger_data->priority;
+ char priority_char = log_characters[priority];
+ uint64_t tid = GetThreadId();
+
+ if (logger_data->file != nullptr) {
+ fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n",
+ logger_data->tag ? logger_data->tag : "nullptr", priority_char, timestamp, getpid(),
+ tid, logger_data->file, logger_data->line, message);
+ } else {
+ fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n",
+ logger_data->tag ? logger_data->tag : "nullptr", priority_char, timestamp, getpid(),
+ tid, message);
+ }
+}
+
+void __android_log_logd_logger(const struct __android_logger_data* logger_data,
+ const char* message) {
+ int buffer_id = logger_data->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : logger_data->buffer_id;
+
+ struct iovec vec[3];
+ vec[0].iov_base =
+ const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&logger_data->priority));
+ vec[0].iov_len = 1;
+ vec[1].iov_base = const_cast<void*>(static_cast<const void*>(logger_data->tag));
+ vec[1].iov_len = strlen(logger_data->tag) + 1;
+ vec[2].iov_base = const_cast<void*>(static_cast<const void*>(message));
+ vec[2].iov_len = strlen(message) + 1;
+
+ write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
+}
int __android_log_write(int prio, const char* tag, const char* msg) {
return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
}
-int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
- if (!tag) tag = "";
+void __android_log_write_logger_data(__android_logger_data* logger_data, const char* msg) {
+ if (logger_data->tag == nullptr) logger_data->tag = "";
#if __BIONIC__
- if (prio == ANDROID_LOG_FATAL) {
+ if (logger_data->priority == ANDROID_LOG_FATAL) {
android_set_abort_message(msg);
}
#endif
- struct iovec vec[3];
- vec[0].iov_base = (unsigned char*)&prio;
- vec[0].iov_len = 1;
- vec[1].iov_base = (void*)tag;
- vec[1].iov_len = strlen(tag) + 1;
- vec[2].iov_base = (void*)msg;
- vec[2].iov_len = strlen(msg) + 1;
+ auto lock = std::shared_lock{logger_function_lock};
+ logger_function(logger_data, msg);
+}
- return write_to_log(static_cast<log_id_t>(bufID), vec, 3);
+int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
+ __android_logger_data logger_data = {sizeof(__android_logger_data), bufID, prio, tag, nullptr, 0};
+ __android_log_write_logger_data(&logger_data, msg);
+ return 1;
}
int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) {
@@ -239,8 +352,8 @@
TEMP_FAILURE_RETRY(write(2, "\n", 1));
__android_log_write(ANDROID_LOG_FATAL, tag, buf);
- abort(); /* abort so we have a chance to debug the situation */
- /* NOTREACHED */
+ __android_log_call_aborter(buf);
+ abort();
}
int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 2b2327c..a53c92b 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -24,6 +24,8 @@
#include <sys/_system_properties.h>
#include <unistd.h>
+#include <algorithm>
+
#include <private/android_logger.h>
static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
@@ -87,7 +89,7 @@
}
}
-static int __android_log_level(const char* tag, size_t len, int default_prio) {
+static int __android_log_level(const char* tag, size_t len) {
/* sizeof() is used on this array below */
static const char log_namespace[] = "persist.log.tag.";
static const size_t base_offset = 8; /* skip "persist." */
@@ -256,20 +258,30 @@
case 'F': /* FALLTHRU */ /* Not officially supported */
case 'A': return ANDROID_LOG_FATAL;
case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
- case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
+ case 'S': return ANDROID_LOG_SILENT;
/* clang-format on */
}
- return default_prio;
+ return -1;
}
int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
- int logLevel = __android_log_level(tag, len, default_prio);
- return logLevel >= 0 && prio >= logLevel;
+ int minimum_log_priority = __android_log_get_minimum_priority();
+ int property_log_level = __android_log_level(tag, len);
+
+ if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
+ return prio >= std::min(property_log_level, minimum_log_priority);
+ } else if (property_log_level >= 0) {
+ return prio >= property_log_level;
+ } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
+ return prio >= minimum_log_priority;
+ } else {
+ return prio >= default_prio;
+ }
}
int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
- int logLevel = __android_log_level(tag, (tag && *tag) ? strlen(tag) : 0, default_prio);
- return logLevel >= 0 && prio >= logLevel;
+ auto len = tag ? strlen(tag) : 0;
+ return __android_log_is_loggable_len(prio, tag, len, default_prio);
}
int __android_log_is_debuggable() {
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index f58c524..3288954 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -54,6 +54,7 @@
],
srcs: [
"libc_test.cpp",
+ "liblog_global_state.cpp",
"liblog_test.cpp",
"log_id_test.cpp",
"log_radio_test.cpp",
diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp
new file mode 100644
index 0000000..8d73bb8
--- /dev/null
+++ b/liblog/tests/liblog_global_state.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "global_state_test_tag"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/log.h>
+
+#include <gtest/gtest.h>
+
+TEST(liblog_global_state, libbase_logs_with_libbase_SetLogger) {
+ using namespace android::base;
+ bool message_seen = false;
+ LogSeverity expected_severity = WARNING;
+ std::string expected_file = Basename(__FILE__);
+ unsigned int expected_line;
+ std::string expected_message = "libbase test message";
+
+ auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
+ unsigned int line, const char* message) {
+ message_seen = true;
+ EXPECT_EQ(DEFAULT, log_id);
+ EXPECT_EQ(expected_severity, severity);
+ EXPECT_STREQ(LOG_TAG, tag);
+ EXPECT_EQ(expected_file, file);
+ EXPECT_EQ(expected_line, line);
+ EXPECT_EQ(expected_message, message);
+ };
+
+ SetLogger(LoggerFunction);
+
+ expected_line = __LINE__ + 1;
+ LOG(expected_severity) << expected_message;
+ EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, libbase_logs_with_liblog_set_logger) {
+ using namespace android::base;
+ // These must be static since they're used by the liblog logger function, which only accepts
+ // lambdas without captures. The items used by the libbase logger are explicitly not static, to
+ // ensure that lambdas with captures do work there.
+ static bool message_seen = false;
+ static std::string expected_file = Basename(__FILE__);
+ static unsigned int expected_line;
+ static std::string expected_message = "libbase test message";
+
+ auto liblog_logger_function = [](const struct __android_logger_data* logger_data,
+ const char* message) {
+ message_seen = true;
+ EXPECT_EQ(sizeof(__android_logger_data), logger_data->struct_size);
+ EXPECT_EQ(LOG_ID_DEFAULT, logger_data->buffer_id);
+ EXPECT_EQ(ANDROID_LOG_WARN, logger_data->priority);
+ EXPECT_STREQ(LOG_TAG, logger_data->tag);
+ EXPECT_EQ(expected_file, logger_data->file);
+ EXPECT_EQ(expected_line, logger_data->line);
+ EXPECT_EQ(expected_message, message);
+ };
+
+ __android_log_set_logger(liblog_logger_function);
+
+ expected_line = __LINE__ + 1;
+ LOG(WARNING) << expected_message;
+ EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, liblog_logs_with_libbase_SetLogger) {
+ using namespace android::base;
+ bool message_seen = false;
+ std::string expected_message = "libbase test message";
+
+ auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
+ unsigned int line, const char* message) {
+ message_seen = true;
+ EXPECT_EQ(MAIN, log_id);
+ EXPECT_EQ(WARNING, severity);
+ EXPECT_STREQ(LOG_TAG, tag);
+ EXPECT_EQ(nullptr, file);
+ EXPECT_EQ(0U, line);
+ EXPECT_EQ(expected_message, message);
+ };
+
+ SetLogger(LoggerFunction);
+
+ __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, LOG_TAG, expected_message.c_str());
+ EXPECT_TRUE(message_seen);
+ message_seen = false;
+}
+
+TEST(liblog_global_state, liblog_logs_with_liblog_set_logger) {
+ using namespace android::base;
+ // These must be static since they're used by the liblog logger function, which only accepts
+ // lambdas without captures. The items used by the libbase logger are explicitly not static, to
+ // ensure that lambdas with captures do work there.
+ static bool message_seen = false;
+ static int expected_buffer_id = LOG_ID_MAIN;
+ static int expected_priority = ANDROID_LOG_WARN;
+ static std::string expected_message = "libbase test message";
+
+ auto liblog_logger_function = [](const struct __android_logger_data* logger_data,
+ const char* message) {
+ message_seen = true;
+ EXPECT_EQ(sizeof(__android_logger_data), logger_data->struct_size);
+ EXPECT_EQ(expected_buffer_id, logger_data->buffer_id);
+ EXPECT_EQ(expected_priority, logger_data->priority);
+ EXPECT_STREQ(LOG_TAG, logger_data->tag);
+ EXPECT_STREQ(nullptr, logger_data->file);
+ EXPECT_EQ(0U, logger_data->line);
+ EXPECT_EQ(expected_message, message);
+ };
+
+ __android_log_set_logger(liblog_logger_function);
+
+ __android_log_buf_write(expected_buffer_id, expected_priority, LOG_TAG, expected_message.c_str());
+ EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, SetAborter_with_liblog) {
+ using namespace android::base;
+
+ std::string expected_message = "libbase test message";
+ static bool message_seen = false;
+ auto aborter_function = [&](const char* message) {
+ message_seen = true;
+ EXPECT_EQ(expected_message, message);
+ };
+
+ SetAborter(aborter_function);
+ LOG(FATAL) << expected_message;
+ EXPECT_TRUE(message_seen);
+ message_seen = false;
+
+ static std::string expected_message_static = "libbase test message";
+ auto liblog_aborter_function = [](const char* message) {
+ message_seen = true;
+ EXPECT_EQ(expected_message_static, message);
+ };
+ __android_log_set_aborter(liblog_aborter_function);
+ LOG(FATAL) << expected_message_static;
+ EXPECT_TRUE(message_seen);
+ message_seen = false;
+}
+
+TEST(liblog_global_state, is_loggable_both_default) {
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+}
+
+TEST(liblog_global_state, is_loggable_minimum_log_priority_only) {
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ EXPECT_EQ(android::base::WARNING, android::base::SetMinimumLogSeverity(android::base::DEBUG));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ EXPECT_EQ(android::base::DEBUG, android::base::SetMinimumLogSeverity(android::base::WARNING));
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+}
+
+TEST(liblog_global_state, is_loggable_tag_log_priority_only) {
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ auto log_tag_property = std::string("log.tag.") + LOG_TAG;
+ android::base::SetProperty(log_tag_property, "d");
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ android::base::SetProperty(log_tag_property, "w");
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ android::base::SetProperty(log_tag_property, "");
+}
+
+TEST(liblog_global_state, is_loggable_both_set) {
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ // When both a tag and a minimum priority are set, we use the lower value of the two.
+
+ // tag = warning, minimum_priority = debug, expect 'debug'
+ auto log_tag_property = std::string("log.tag.") + LOG_TAG;
+ android::base::SetProperty(log_tag_property, "w");
+ EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ // tag = warning, minimum_priority = warning, expect 'warning'
+ EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ // tag = debug, minimum_priority = warning, expect 'debug'
+ android::base::SetProperty(log_tag_property, "d");
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ // tag = debug, minimum_priority = debug, expect 'debug'
+ EXPECT_EQ(ANDROID_LOG_WARN, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+ EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+ android::base::SetProperty(log_tag_property, "");
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index c402e20..75a26bf 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1074,7 +1074,6 @@
// Once we've found our expected entry, break.
if (len == LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag)) {
- EXPECT_EQ(ret, len + static_cast<ssize_t>(sizeof(big_payload_tag)));
*found = true;
}
};
@@ -1259,14 +1258,10 @@
int level;
char type;
} levels[] = {
- { ANDROID_LOG_VERBOSE, 'v' },
- { ANDROID_LOG_DEBUG, 'd' },
- { ANDROID_LOG_INFO, 'i' },
- { ANDROID_LOG_WARN, 'w' },
- { ANDROID_LOG_ERROR, 'e' },
- { ANDROID_LOG_FATAL, 'a' },
- { -1, 's' },
- { -2, 'g' }, // Illegal value, resort to default
+ {ANDROID_LOG_VERBOSE, 'v'}, {ANDROID_LOG_DEBUG, 'd'},
+ {ANDROID_LOG_INFO, 'i'}, {ANDROID_LOG_WARN, 'w'},
+ {ANDROID_LOG_ERROR, 'e'}, {ANDROID_LOG_FATAL, 'a'},
+ {ANDROID_LOG_SILENT, 's'}, {-2, 'g'}, // Illegal value, resort to default
};
// Set up initial test condition
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
index 9194cf3..2efd49c 100644
--- a/libprocinfo/process.cpp
+++ b/libprocinfo/process.cpp
@@ -59,7 +59,6 @@
case 'Z':
return kProcessStateZombie;
default:
- LOG(ERROR) << "unknown process state: " << *state;
return kProcessStateUnknown;
}
}
diff --git a/libutils/StrongPointer_test.cpp b/libutils/StrongPointer_test.cpp
index 153cf96..7b2e37f 100644
--- a/libutils/StrongPointer_test.cpp
+++ b/libutils/StrongPointer_test.cpp
@@ -56,3 +56,18 @@
}
ASSERT_TRUE(isDeleted) << "foo was leaked!";
}
+
+TEST(StrongPointer, NullptrComparison) {
+ sp<SPFoo> foo;
+ ASSERT_EQ(foo, nullptr);
+ ASSERT_EQ(nullptr, foo);
+}
+
+TEST(StrongPointer, PointerComparison) {
+ bool isDeleted;
+ sp<SPFoo> foo = new SPFoo(&isDeleted);
+ ASSERT_EQ(foo.get(), foo);
+ ASSERT_EQ(foo, foo.get());
+ ASSERT_NE(nullptr, foo);
+ ASSERT_NE(foo, nullptr);
+}
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 100e507..6f4fb47 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -27,43 +27,6 @@
// ---------------------------------------------------------------------------
-// TODO: Maybe remove sp<> ? wp<> comparison? These are dangerous: If the wp<>
-// was created before the sp<>, and they point to different objects, they may
-// compare equal even if they are entirely unrelated. E.g. CameraService
-// currently performa such comparisons.
-
-#define COMPARE_STRONG(_op_) \
-template<typename U> \
-inline bool operator _op_ (const sp<U>& o) const { \
- return m_ptr _op_ o.m_ptr; \
-} \
-template<typename U> \
-inline bool operator _op_ (const U* o) const { \
- return m_ptr _op_ o; \
-} \
-/* Needed to handle type inference for nullptr: */ \
-inline bool operator _op_ (const T* o) const { \
- return m_ptr _op_ o; \
-}
-
-template<template<typename C> class comparator, typename T, typename U>
-static inline bool _sp_compare_(T* a, U* b) {
- return comparator<typename std::common_type<T*, U*>::type>()(a, b);
-}
-
-// Use std::less and friends to avoid undefined behavior when ordering pointers
-// to different objects.
-#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_) \
-template<typename U> \
-inline bool operator _op_ (const sp<U>& o) const { \
- return _sp_compare_<_compare_>(m_ptr, o.m_ptr); \
-} \
-template<typename U> \
-inline bool operator _op_ (const U* o) const { \
- return _sp_compare_<_compare_>(m_ptr, o); \
-}
-// ---------------------------------------------------------------------------
-
template<typename T>
class sp {
public:
@@ -102,15 +65,6 @@
inline T* get() const { return m_ptr; }
inline explicit operator bool () const { return m_ptr != nullptr; }
- // Operators
-
- COMPARE_STRONG(==)
- COMPARE_STRONG(!=)
- COMPARE_STRONG_FUNCTIONAL(>, std::greater)
- COMPARE_STRONG_FUNCTIONAL(<, std::less)
- COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
- COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
-
// Punt these to the wp<> implementation.
template<typename U>
inline bool operator == (const wp<U>& o) const {
@@ -130,13 +84,69 @@
T* m_ptr;
};
-// For code size reasons, we do not want these inlined or templated.
-void sp_report_race();
-void sp_report_stack_pointer();
+#define COMPARE_STRONG(_op_) \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
+ return t.get() _op_ u.get(); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const T* t, const sp<U>& u) { \
+ return t _op_ u.get(); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const U* u) { \
+ return t.get() _op_ u; \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
+ return t.get() _op_ nullptr; \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
+ return nullptr _op_ t.get(); \
+ }
+
+template <template <typename C> class comparator, typename T, typename U>
+static inline bool _sp_compare_(T* a, U* b) {
+ return comparator<typename std::common_type<T*, U*>::type>()(a, b);
+}
+
+#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_) \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
+ return _sp_compare_<_compare_>(t.get(), u.get()); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const T* t, const sp<U>& u) { \
+ return _sp_compare_<_compare_>(t, u.get()); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const U* u) { \
+ return _sp_compare_<_compare_>(t.get(), u); \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
+ return _sp_compare_<_compare_>(t.get(), nullptr); \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
+ return _sp_compare_<_compare_>(nullptr, t.get()); \
+ }
+
+COMPARE_STRONG(==)
+COMPARE_STRONG(!=)
+COMPARE_STRONG_FUNCTIONAL(>, std::greater)
+COMPARE_STRONG_FUNCTIONAL(<, std::less)
+COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
+COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
#undef COMPARE_STRONG
#undef COMPARE_STRONG_FUNCTIONAL
+// For code size reasons, we do not want these inlined or templated.
+void sp_report_race();
+void sp_report_stack_pointer();
+
// ---------------------------------------------------------------------------
// No user serviceable parts below here.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0b89909..6a6169c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -945,14 +945,33 @@
on property:sys.sysctl.tcp_def_init_rwnd=*
write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
-on property:security.perf_harden=0
+# perf_event_open syscall security:
+# Newer kernels have the ability to control the use of the syscall via SELinux
+# hooks. init tests for this, and sets sys_init.perf_lsm_hooks to 1 if the
+# kernel has the hooks. In this case, the system-wide perf_event_paranoid
+# sysctl is set to -1 (unrestricted use), and the SELinux policy is used for
+# controlling access. On older kernels, the paranoid value is the only means of
+# controlling access. It is normally 3 (allow only root), but the shell user
+# can lower it to 1 (allowing thread-scoped pofiling) via security.perf_harden.
+on property:sys.init.perf_lsm_hooks=1
+ write /proc/sys/kernel/perf_event_paranoid -1
+on property:security.perf_harden=0 && property:sys.init.perf_lsm_hooks=""
write /proc/sys/kernel/perf_event_paranoid 1
+on property:security.perf_harden=1 && property:sys.init.perf_lsm_hooks=""
+ write /proc/sys/kernel/perf_event_paranoid 3
+
+# Additionally, simpleperf profiler uses debug.* and security.perf_harden
+# sysprops to be able to indirectly set these sysctls.
+on property:security.perf_harden=0
write /proc/sys/kernel/perf_event_max_sample_rate ${debug.perf_event_max_sample_rate:-100000}
write /proc/sys/kernel/perf_cpu_time_max_percent ${debug.perf_cpu_time_max_percent:-25}
write /proc/sys/kernel/perf_event_mlock_kb ${debug.perf_event_mlock_kb:-516}
-
+# Default values.
on property:security.perf_harden=1
- write /proc/sys/kernel/perf_event_paranoid 3
+ write /proc/sys/kernel/perf_event_max_sample_rate 100000
+ write /proc/sys/kernel/perf_cpu_time_max_percent 25
+ write /proc/sys/kernel/perf_event_mlock_kb 516
+
# on shutdown
# In device's init.rc, this trigger can be used to do device-specific actions
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index d391cc1..3bee875 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -218,25 +218,28 @@
bzip2: bzcat bzip2 bunzip2
+gavinhoward/bc: bc
+
one-true-awk: awk
toolbox: getevent getprop setprop start stop
-toybox: acpi base64 basename bc blkid blockdev cal cat chattr chcon chgrp
-chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd df
-diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
-false fgrep file find flock fmt free freeramdisk fsfreeze getconf
-getenforce getfattr grep groups gunzip gzip head help hostname hwclock
-i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd insmod
-install ionice iorenice iotop kill killall ln load\_policy log logname
-losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
+toybox: acpi base64 basename blkid blockdev cal cat chattr chcon chgrp chmod
+chown chroot chrt cksum clear cmp comm cp cpio cut date dd devmem
+df diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
+false fgrep file find flock fmt free freeramdisk fsfreeze fsync getconf
+getenforce getfattr getopt grep groups gunzip gzip head help hostname
+hwclock i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd
+insmod install ionice iorenice iotop kill killall ln load\_policy log
+logname losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint
mv nbd-client nc netcat netstat nice nl nohup nproc nsenter od partprobe
paste patch pgrep pidof ping ping6 pivot\_root pkill pmap printenv
-printf prlimit ps pwd pwdx readlink realpath renice restorecon rev
-rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
-setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort split
-stat strings stty swapoff swapon sync sysctl tac tail tar taskset tee
-time timeout top touch tr traceroute traceroute6 true truncate tty tunctl
-ulimit umount uname uniq unix2dos unlink unshare uptime usleep uudecode
-uuencode uuidgen vconfig vmstat watch wc which whoami xargs xxd yes zcat
+printf prlimit ps pwd pwdx readelf readlink realpath renice restorecon
+rev rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
+setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort
+split stat strings stty swapoff swapon sync sysctl tac tail tar taskset
+tee time timeout top touch tr traceroute traceroute6 true truncate
+tty tunctl ulimit umount uname uniq unix2dos unlink unshare uptime
+usleep uudecode uuencode uuidgen vconfig vi vmstat watch wc which
+whoami xargs xxd yes zcat