Merge "Add DwarfSection classes."
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index fc32469..9477c56 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -427,11 +427,15 @@
static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event,
void*) {
- if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
- device_connected(device);
- } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
- device_disconnected(device);
- }
+ // We're called with the libusb lock taken. Call these on the main thread outside of this
+ // function so that the usb_handle mutex is always taken before the libusb mutex.
+ fdevent_run_on_main_thread([device, event]() {
+ if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
+ device_connected(device);
+ } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) {
+ device_disconnected(device);
+ }
+ });
return 0;
}
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index fa0d922..548b286 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -176,15 +176,19 @@
// Provides an expression that evaluates to the truthiness of `x`, automatically
// aborting if `c` is true.
#define ABORT_AFTER_LOG_EXPR_IF(c, x) (((c) && ::android::base::LogAbortAfterFullExpr()) || (x))
+// Note to the static analyzer that we always execute FATAL logs in practice.
+#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)
// Defines whether the given severity will be logged or silently swallowed.
#define WOULD_LOG(severity) \
- UNLIKELY((SEVERITY_LAMBDA(severity)) >= ::android::base::GetMinimumLogSeverity())
+ (UNLIKELY((SEVERITY_LAMBDA(severity)) >= ::android::base::GetMinimumLogSeverity()) || \
+ MUST_LOG_MESSAGE(severity))
// Get an ostream that can be used for logging at the given severity and to the default
// destination.
@@ -315,7 +319,7 @@
// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally
// CHECK should be used unless profiling identifies a CHECK as being in
// performance critical code.
-#if defined(NDEBUG)
+#if defined(NDEBUG) && !defined(__clang_analyzer__)
static constexpr bool kEnableDChecks = false;
#else
static constexpr bool kEnableDChecks = true;
@@ -339,7 +343,7 @@
if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2)
#define DCHECK_STRNE(s1, s2) \
if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2)
-#if defined(NDEBUG)
+#if defined(NDEBUG) && !defined(__clang_analyzer__)
#define DCHECK_CONSTEXPR(x, out, dummy)
#else
#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index d4e215e..a4c2160 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -201,8 +201,10 @@
BootEventRecordStore boot_event_store;
BootEventRecordStore::BootEventRecord record;
- if (!boot_event_store.GetBootEvent(kBuildDateKey, &record) ||
- build_date != record.second) {
+ if (!boot_event_store.GetBootEvent(kBuildDateKey, &record)) {
+ boot_complete_prefix = "factory_reset_" + boot_complete_prefix;
+ boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
+ } else if (build_date != record.second) {
boot_complete_prefix = "ota_" + boot_complete_prefix;
boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
}
@@ -241,7 +243,7 @@
for (const auto& stageTiming : stages) {
// |stageTiming| is of the form 'stage:time'.
auto stageTimingValues = android::base::Split(stageTiming, ":");
- DCHECK_EQ(2, stageTimingValues.size());
+ DCHECK_EQ(2U, stageTimingValues.size());
std::string stageName = stageTimingValues[0];
int32_t time_ms;
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 3a80b50..5565cfd 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -11,6 +11,11 @@
local_include_dirs: ["include"],
}
+cc_library_headers {
+ name: "libdebuggerd_common_headers",
+ export_include_dirs: ["common/include"]
+}
+
cc_library_shared {
name: "libtombstoned_client",
defaults: ["debuggerd_defaults"],
@@ -19,15 +24,18 @@
"util.cpp",
],
+ header_libs: ["libdebuggerd_common_headers"],
+
static_libs: [
- "libasync_safe"
+ "libasync_safe",
],
shared_libs: [
- "libcutils",
"libbase",
+ "libcutils",
],
+ export_header_lib_headers: ["libdebuggerd_common_headers"],
export_include_dirs: ["tombstoned/include"]
}
@@ -40,12 +48,15 @@
"util.cpp",
],
+ header_libs: ["libdebuggerd_common_headers"],
+
whole_static_libs: [
"libasync_safe",
"libcutils",
"libbase",
],
+ export_header_lib_headers: ["libdebuggerd_common_headers"],
export_include_dirs: ["tombstoned/include"]
}
@@ -55,11 +66,14 @@
defaults: ["debuggerd_defaults"],
srcs: ["handler/debuggerd_handler.cpp"],
+ header_libs: ["libdebuggerd_common_headers"],
+
whole_static_libs: [
"libasync_safe",
"libdebuggerd",
],
+ export_header_lib_headers: ["libdebuggerd_common_headers"],
export_include_dirs: ["include"],
}
@@ -107,11 +121,14 @@
"util.cpp",
],
+ header_libs: ["libdebuggerd_common_headers"],
+
shared_libs: [
"libbase",
"libcutils",
],
+ export_header_lib_headers: ["libdebuggerd_common_headers"],
export_include_dirs: ["include"],
}
@@ -191,7 +208,8 @@
"libbase",
"libcutils",
"libdebuggerd_client",
- "liblog"
+ "liblog",
+ "libnativehelper"
],
static_libs: [
@@ -271,6 +289,8 @@
],
defaults: ["debuggerd_defaults"],
+ header_libs: ["libdebuggerd_common_headers"],
+
static_libs: [
"libbase",
"libcutils",
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 4ce038c..cb7cbbe 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -28,7 +28,9 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
@@ -40,10 +42,12 @@
using android::base::unique_fd;
-static bool send_signal(pid_t pid, bool backtrace) {
+static bool send_signal(pid_t pid, const DebuggerdDumpType dump_type) {
+ const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : DEBUGGER_SIGNAL;
sigval val;
- val.sival_int = backtrace;
- if (sigqueue(pid, DEBUGGER_SIGNAL, val) != 0) {
+ val.sival_int = (dump_type == kDebuggerdNativeBacktrace) ? 1 : 0;
+
+ if (sigqueue(pid, signal, val) != 0) {
PLOG(ERROR) << "libdebuggerd_client: failed to send signal to pid " << pid;
return false;
}
@@ -58,8 +62,8 @@
tv->tv_usec = static_cast<long>(microseconds.count());
}
-bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType dump_type,
- unsigned int timeout_ms) {
+bool debuggerd_trigger_dump(pid_t pid, DebuggerdDumpType dump_type, unsigned int timeout_ms,
+ unique_fd output_fd) {
LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
unique_fd sockfd;
const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
@@ -102,7 +106,7 @@
return false;
}
- InterceptRequest req = {.pid = pid };
+ InterceptRequest req = {.pid = pid, .dump_type = dump_type};
if (!set_timeout(sockfd)) {
PLOG(ERROR) << "libdebugger_client: failed to set timeout";
return false;
@@ -115,6 +119,20 @@
return false;
}
+ std::string pipe_size_str;
+ int pipe_buffer_size = 1024 * 1024;
+ if (android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
+ pipe_size_str = android::base::Trim(pipe_size_str);
+
+ if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
+ LOG(FATAL) << "failed to parse pipe max size '" << pipe_size_str << "'";
+ }
+ }
+
+ if (fcntl(pipe_read.get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
+ PLOG(ERROR) << "failed to set pipe buffer size";
+ }
+
if (send_fd(set_timeout(sockfd), &req, sizeof(req), std::move(pipe_write)) != sizeof(req)) {
PLOG(ERROR) << "libdebuggerd_client: failed to send output fd to tombstoned";
return false;
@@ -140,8 +158,7 @@
return false;
}
- bool backtrace = dump_type == kDebuggerdBacktrace;
- if (!send_signal(pid, backtrace)) {
+ if (!send_signal(pid, dump_type)) {
return false;
}
@@ -210,15 +227,16 @@
return true;
}
-int dump_backtrace_to_file(pid_t tid, int fd) {
- return dump_backtrace_to_file_timeout(tid, fd, 0);
+int dump_backtrace_to_file(pid_t tid, DebuggerdDumpType dump_type, int fd) {
+ return dump_backtrace_to_file_timeout(tid, dump_type, 0, fd);
}
-int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) {
+int dump_backtrace_to_file_timeout(pid_t tid, DebuggerdDumpType dump_type, int timeout_secs,
+ int fd) {
android::base::unique_fd copy(dup(fd));
if (copy == -1) {
return -1;
}
int timeout_ms = timeout_secs > 0 ? timeout_secs * 1000 : 0;
- return debuggerd_trigger_dump(tid, std::move(copy), kDebuggerdBacktrace, timeout_ms) ? 0 : -1;
+ return debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1;
}
diff --git a/debuggerd/client/debuggerd_client_test.cpp b/debuggerd/client/debuggerd_client_test.cpp
index 8f97db1..8420f03 100644
--- a/debuggerd/client/debuggerd_client_test.cpp
+++ b/debuggerd/client/debuggerd_client_test.cpp
@@ -67,7 +67,8 @@
// Wait for a bit to let the child spawn all of its threads.
std::this_thread::sleep_for(250ms);
- ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(pipe_write), kDebuggerdBacktrace, 10000));
+ ASSERT_TRUE(
+ debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 10000, std::move(pipe_write)));
// Immediately kill the forked child, to make sure that the dump didn't return early.
ASSERT_EQ(0, kill(forkpid, SIGKILL)) << strerror(errno);
@@ -107,5 +108,6 @@
unique_fd output_read, output_write;
ASSERT_TRUE(Pipe(&output_read, &output_write));
- ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(output_write), kDebuggerdBacktrace, 0));
+ ASSERT_TRUE(
+ debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 0, std::move(output_write)));
}
diff --git a/debuggerd/common/include/dump_type.h b/debuggerd/common/include/dump_type.h
new file mode 100644
index 0000000..203269e
--- /dev/null
+++ b/debuggerd/common/include/dump_type.h
@@ -0,0 +1,49 @@
+#pragma once
+
+/*
+ * Copyright 2017, 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 <sys/types.h>
+
+#include <ostream>
+
+enum DebuggerdDumpType : uint8_t {
+ kDebuggerdNativeBacktrace,
+ kDebuggerdTombstone,
+ kDebuggerdJavaBacktrace,
+ kDebuggerdAnyIntercept
+};
+
+inline std::ostream& operator<<(std::ostream& stream, const DebuggerdDumpType& rhs) {
+ switch (rhs) {
+ case kDebuggerdNativeBacktrace:
+ stream << "kDebuggerdNativeBacktrace";
+ break;
+ case kDebuggerdTombstone:
+ stream << "kDebuggerdTombstone";
+ break;
+ case kDebuggerdJavaBacktrace:
+ stream << "kDebuggerdJavaBacktrace";
+ break;
+ case kDebuggerdAnyIntercept:
+ stream << "kDebuggerdAnyIntercept";
+ break;
+ default:
+ stream << "[unknown]";
+ }
+
+ return stream;
+}
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index be28079..558bc72 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -41,6 +41,7 @@
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#include <log/log.h>
+#include <private/android_filesystem_config.h>
#include <procinfo/process.h>
#include "backtrace.h"
@@ -99,8 +100,9 @@
return true;
}
-static bool activity_manager_notify(int pid, int signal, const std::string& amfd_data) {
- android::base::unique_fd amfd(socket_local_client("/data/system/ndebugsocket", ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM));
+static bool activity_manager_notify(pid_t pid, int signal, const std::string& amfd_data) {
+ android::base::unique_fd amfd(socket_local_client(
+ "/data/system/ndebugsocket", ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM));
if (amfd.get() == -1) {
PLOG(ERROR) << "unable to connect to activity manager";
return false;
@@ -150,13 +152,13 @@
_exit(1);
}
-static void abort_handler(pid_t target, const bool& tombstoned_connected,
+static void abort_handler(pid_t target, const bool tombstoned_connected,
unique_fd& tombstoned_socket, unique_fd& output_fd,
const char* abort_msg) {
// If we abort before we get an output fd, contact tombstoned to let any
// potential listeners know that we failed.
if (!tombstoned_connected) {
- if (!tombstoned_connect(target, &tombstoned_socket, &output_fd)) {
+ if (!tombstoned_connect(target, &tombstoned_socket, &output_fd, kDebuggerdAnyIntercept)) {
// We failed to connect, not much we can do.
LOG(ERROR) << "failed to connected to tombstoned to report failure";
_exit(1);
@@ -207,12 +209,19 @@
action.sa_handler = signal_handler;
debuggerd_register_handlers(&action);
- if (argc != 3) {
- return 1;
+ sigset_t mask;
+ sigemptyset(&mask);
+ if (sigprocmask(SIG_SETMASK, &mask, nullptr) != 0) {
+ PLOG(FATAL) << "failed to set signal mask";
+ }
+
+ if (argc != 4) {
+ LOG(FATAL) << "Wrong number of args: " << argc << " (expected 4)";
}
pid_t main_tid;
pid_t pseudothread_tid;
+ int dump_type;
if (!android::base::ParseInt(argv[1], &main_tid, 1, std::numeric_limits<pid_t>::max())) {
LOG(FATAL) << "invalid main tid: " << argv[1];
@@ -222,6 +231,10 @@
LOG(FATAL) << "invalid pseudothread tid: " << argv[2];
}
+ if (!android::base::ParseInt(argv[3], &dump_type, 0, 1)) {
+ LOG(FATAL) << "invalid requested dump type: " << argv[3];
+ }
+
if (target == 1) {
LOG(FATAL) << "target died before we could attach (received main tid = " << main_tid << ")";
}
@@ -258,7 +271,7 @@
}
// Die if we take too long.
- alarm(20);
+ alarm(2);
std::string attach_error;
@@ -305,8 +318,9 @@
// Drop our capabilities now that we've attached to the threads we care about.
drop_capabilities();
- LOG(INFO) << "obtaining output fd from tombstoned";
- tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd);
+ const DebuggerdDumpType dump_type_enum = static_cast<DebuggerdDumpType>(dump_type);
+ LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type_enum;
+ tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum);
// Write a '\1' to stdout to tell the crashing process to resume.
// It also restores the value of PR_SET_DUMPABLE at this point.
@@ -401,7 +415,10 @@
}
if (fatal_signal) {
- activity_manager_notify(target, signo, amfd_data);
+ // Don't try to notify ActivityManager if it just crashed, or we might hang until timeout.
+ if (target_info.name != "system_server" || target_info.uid != AID_SYSTEM) {
+ activity_manager_notify(target, signo, amfd_data);
+ }
}
// Close stdout before we notify tombstoned of completion.
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 4997dd6..6298ace 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -72,8 +72,8 @@
}
std::thread redirect_thread = spawn_redirect_thread(std::move(piperead));
- if (!debuggerd_trigger_dump(pid, std::move(pipewrite),
- backtrace_only ? kDebuggerdBacktrace : kDebuggerdTombstone, 0)) {
+ if (!debuggerd_trigger_dump(pid, backtrace_only ? kDebuggerdNativeBacktrace : kDebuggerdTombstone,
+ 0, std::move(pipewrite))) {
redirect_thread.join();
errx(1, "failed to dump process %d", pid);
}
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index f17724a..9008b95 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -88,14 +88,15 @@
} \
} while (0)
-static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd) {
+static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
+ DebuggerdDumpType intercept_type) {
intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
if (intercept_fd->get() == -1) {
FAIL() << "failed to contact tombstoned: " << strerror(errno);
}
- InterceptRequest req = {.pid = target_pid};
+ InterceptRequest req = {.pid = target_pid, .dump_type = intercept_type};
unique_fd output_pipe_write;
if (!Pipe(output_fd, &output_pipe_write)) {
@@ -118,6 +119,8 @@
FAIL() << "failed to set pipe size: " << strerror(errno);
}
+ ASSERT_GE(pipe_buffer_size, 1024 * 1024);
+
if (send_fd(intercept_fd->get(), &req, sizeof(req), std::move(output_pipe_write)) != sizeof(req)) {
FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
}
@@ -146,7 +149,7 @@
CrasherTest();
~CrasherTest();
- void StartIntercept(unique_fd* output_fd);
+ void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
// Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
void FinishIntercept(int* result);
@@ -172,12 +175,12 @@
android::base::SetProperty(kWaitForGdbKey, previous_wait_for_gdb ? "1" : "0");
}
-void CrasherTest::StartIntercept(unique_fd* output_fd) {
+void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
if (crasher_pid == -1) {
FAIL() << "crasher hasn't been started";
}
- tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd);
+ tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, intercept_type);
}
void CrasherTest::FinishIntercept(int* result) {
@@ -428,7 +431,7 @@
StartProcess([]() {
abort();
});
- StartIntercept(&output_fd);
+ StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
std::this_thread::sleep_for(500ms);
@@ -595,11 +598,11 @@
pid_t pid = 123'456'789 + i;
unique_fd intercept_fd, output_fd;
- tombstoned_intercept(pid, &intercept_fd, &output_fd);
+ tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
{
unique_fd tombstoned_socket, input_fd;
- ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd));
+ ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
}
@@ -627,7 +630,7 @@
pid_t pid = pid_base + dump;
unique_fd intercept_fd, output_fd;
- tombstoned_intercept(pid, &intercept_fd, &output_fd);
+ tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
// Pretend to crash, and then immediately close the socket.
unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
@@ -658,11 +661,11 @@
pid_t pid = pid_base + dump;
unique_fd intercept_fd, output_fd;
- tombstoned_intercept(pid, &intercept_fd, &output_fd);
+ tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
{
unique_fd tombstoned_socket, input_fd;
- ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd));
+ ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
tombstoned_notify_completion(tombstoned_socket.get());
}
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index a9c9862..43104ec 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -151,7 +151,7 @@
// Fetch output fd from tombstoned.
unique_fd tombstone_socket, output_fd;
- if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd)) {
+ if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdNativeBacktrace)) {
goto exit;
}
@@ -215,7 +215,8 @@
}
unique_fd tombstone_socket, output_fd;
- bool tombstoned_connected = tombstoned_connect(getpid(), &tombstone_socket, &output_fd);
+ bool tombstoned_connected =
+ tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdTombstone);
debuggerd_fallback_tombstone(output_fd.get(), ucontext, info, abort_message);
if (tombstoned_connected) {
tombstoned_notify_completion(tombstone_socket.get());
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 8fd6e11..55cd03e 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -50,6 +50,8 @@
#include <async_safe/log.h>
+#include "dump_type.h"
+
// see man(2) prctl, specifically the section about PR_GET_NAME
#define MAX_TASK_NAME_LEN (16)
@@ -253,6 +255,14 @@
// process.
static void* pseudothread_stack;
+static DebuggerdDumpType get_dump_type(const debugger_thread_info* thread_info) {
+ if (thread_info->signal_number == DEBUGGER_SIGNAL && thread_info->info->si_value.sival_int) {
+ return kDebuggerdNativeBacktrace;
+ }
+
+ return kDebuggerdTombstone;
+}
+
static int debuggerd_dispatch_pseudothread(void* arg) {
debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);
@@ -285,11 +295,15 @@
char main_tid[10];
char pseudothread_tid[10];
+ char debuggerd_dump_type[10];
async_safe_format_buffer(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid);
async_safe_format_buffer(pseudothread_tid, sizeof(pseudothread_tid), "%d",
thread_info->pseudothread_tid);
+ async_safe_format_buffer(debuggerd_dump_type, sizeof(debuggerd_dump_type), "%d",
+ get_dump_type(thread_info));
- execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, nullptr);
+ execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type,
+ nullptr);
fatal_errno("exec failed");
} else {
diff --git a/debuggerd/include/debuggerd/client.h b/debuggerd/include/debuggerd/client.h
index 01de57b..b7284b0 100644
--- a/debuggerd/include/debuggerd/client.h
+++ b/debuggerd/include/debuggerd/client.h
@@ -22,15 +22,13 @@
#include <android-base/unique_fd.h>
-enum DebuggerdDumpType {
- kDebuggerdBacktrace,
- kDebuggerdTombstone,
-};
+#include "dump_type.h"
// Trigger a dump of specified process to output_fd.
// output_fd is consumed, timeout of 0 will wait forever.
-bool debuggerd_trigger_dump(pid_t pid, android::base::unique_fd output_fd,
- enum DebuggerdDumpType dump_type, unsigned int timeout_ms);
+bool debuggerd_trigger_dump(pid_t pid, enum DebuggerdDumpType dump_type, unsigned int timeout_ms,
+ android::base::unique_fd output_fd);
-int dump_backtrace_to_file(pid_t tid, int fd);
-int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs);
+int dump_backtrace_to_file(pid_t tid, enum DebuggerdDumpType dump_type, int output_fd);
+int dump_backtrace_to_file_timeout(pid_t tid, enum DebuggerdDumpType dump_type, int timeout_secs,
+ int output_fd);
diff --git a/debuggerd/protocol.h b/debuggerd/protocol.h
index 144efc8..7e1961e 100644
--- a/debuggerd/protocol.h
+++ b/debuggerd/protocol.h
@@ -18,6 +18,8 @@
#include <stdint.h>
+#include "dump_type.h"
+
// Sockets in the ANDROID_SOCKET_NAMESPACE_RESERVED namespace.
// Both sockets are SOCK_SEQPACKET sockets, so no explicit length field is needed.
constexpr char kTombstonedCrashSocketName[] = "tombstoned_crash";
@@ -40,6 +42,7 @@
};
struct DumpRequest {
+ DebuggerdDumpType dump_type;
int32_t pid;
};
@@ -54,10 +57,15 @@
// Comes with a file descriptor via SCM_RIGHTS.
// This packet should be sent before an actual dump happens.
struct InterceptRequest {
+ DebuggerdDumpType dump_type;
int32_t pid;
};
enum class InterceptStatus : uint8_t {
+ // Returned when an intercept of a different type has already been
+ // registered (and is active) for a given PID.
+ kFailedAlreadyRegistered,
+ // Returned in all other failure cases.
kFailed,
kStarted,
kRegistered,
diff --git a/debuggerd/tombstoned/include/tombstoned/tombstoned.h b/debuggerd/tombstoned/include/tombstoned/tombstoned.h
index 908517d..6403dbe 100644
--- a/debuggerd/tombstoned/include/tombstoned/tombstoned.h
+++ b/debuggerd/tombstoned/include/tombstoned/tombstoned.h
@@ -20,7 +20,9 @@
#include <android-base/unique_fd.h>
+#include "dump_type.h"
+
bool tombstoned_connect(pid_t pid, android::base::unique_fd* tombstoned_socket,
- android::base::unique_fd* output_fd, bool is_native_crash = true);
+ android::base::unique_fd* output_fd, DebuggerdDumpType dump_type);
bool tombstoned_notify_completion(int tombstoned_socket);
diff --git a/debuggerd/tombstoned/intercept_manager.cpp b/debuggerd/tombstoned/intercept_manager.cpp
index 4d4eb9e..24960bc 100644
--- a/debuggerd/tombstoned/intercept_manager.cpp
+++ b/debuggerd/tombstoned/intercept_manager.cpp
@@ -61,11 +61,24 @@
reason = "due to input";
}
- LOG(INFO) << "intercept for pid " << intercept->intercept_pid << " terminated " << reason;
+ LOG(INFO) << "intercept for pid " << intercept->intercept_pid << " and type "
+ << intercept->dump_type << " terminated: " << reason;
intercept_manager->intercepts.erase(it);
}
}
+static bool is_intercept_request_valid(const InterceptRequest& request) {
+ if (request.pid <= 0 || request.pid > std::numeric_limits<pid_t>::max()) {
+ return false;
+ }
+
+ if (request.dump_type < 0 || request.dump_type > kDebuggerdJavaBacktrace) {
+ return false;
+ }
+
+ return true;
+}
+
static void intercept_request_cb(evutil_socket_t sockfd, short ev, void* arg) {
auto intercept = reinterpret_cast<Intercept*>(arg);
InterceptManager* intercept_manager = intercept->intercept_manager;
@@ -103,23 +116,24 @@
rcv_fd.reset(moved_fd);
// We trust the other side, so only do minimal validity checking.
- if (intercept_request.pid <= 0 || intercept_request.pid > std::numeric_limits<pid_t>::max()) {
+ if (!is_intercept_request_valid(intercept_request)) {
InterceptResponse response = {};
response.status = InterceptStatus::kFailed;
- snprintf(response.error_message, sizeof(response.error_message), "invalid pid %" PRId32,
- intercept_request.pid);
+ snprintf(response.error_message, sizeof(response.error_message), "invalid intercept request");
TEMP_FAILURE_RETRY(write(sockfd, &response, sizeof(response)));
goto fail;
}
intercept->intercept_pid = intercept_request.pid;
+ intercept->dump_type = intercept_request.dump_type;
// Check if it's already registered.
if (intercept_manager->intercepts.count(intercept_request.pid) > 0) {
InterceptResponse response = {};
- response.status = InterceptStatus::kFailed;
+ response.status = InterceptStatus::kFailedAlreadyRegistered;
snprintf(response.error_message, sizeof(response.error_message),
- "pid %" PRId32 " already intercepted", intercept_request.pid);
+ "pid %" PRId32 " already intercepted, type %d", intercept_request.pid,
+ intercept_request.dump_type);
TEMP_FAILURE_RETRY(write(sockfd, &response, sizeof(response)));
LOG(WARNING) << response.error_message;
goto fail;
@@ -138,7 +152,8 @@
intercept_manager->intercepts[intercept_request.pid] = std::unique_ptr<Intercept>(intercept);
intercept->registered = true;
- LOG(INFO) << "tombstoned registered intercept for pid " << intercept_request.pid;
+ LOG(INFO) << "registered intercept for pid " << intercept_request.pid << " and type "
+ << intercept_request.dump_type;
// Register a different read event on the socket so that we can remove intercepts if the socket
// closes (e.g. if a user CTRL-C's the process that requested the intercept).
@@ -174,16 +189,27 @@
intercept_socket);
}
-bool InterceptManager::GetIntercept(pid_t pid, android::base::unique_fd* out_fd) {
+bool InterceptManager::GetIntercept(pid_t pid, DebuggerdDumpType dump_type,
+ android::base::unique_fd* out_fd) {
auto it = this->intercepts.find(pid);
if (it == this->intercepts.end()) {
return false;
}
+ if (dump_type == kDebuggerdAnyIntercept) {
+ LOG(INFO) << "found registered intercept of type " << it->second->dump_type
+ << " for requested type kDebuggerdAnyIntercept";
+ } else if (it->second->dump_type != dump_type) {
+ LOG(WARNING) << "found non-matching intercept of type " << it->second->dump_type
+ << " for requested type: " << dump_type;
+ return false;
+ }
+
auto intercept = std::move(it->second);
this->intercepts.erase(it);
- LOG(INFO) << "found intercept fd " << intercept->output_fd.get() << " for pid " << pid;
+ LOG(INFO) << "found intercept fd " << intercept->output_fd.get() << " for pid " << pid
+ << " and type " << intercept->dump_type;
InterceptResponse response = {};
response.status = InterceptStatus::kStarted;
TEMP_FAILURE_RETRY(write(intercept->sockfd, &response, sizeof(response)));
diff --git a/debuggerd/tombstoned/intercept_manager.h b/debuggerd/tombstoned/intercept_manager.h
index cb5db62..a11d565 100644
--- a/debuggerd/tombstoned/intercept_manager.h
+++ b/debuggerd/tombstoned/intercept_manager.h
@@ -25,6 +25,8 @@
#include <android-base/unique_fd.h>
+#include "dump_type.h"
+
struct InterceptManager;
struct Intercept {
@@ -39,6 +41,7 @@
pid_t intercept_pid = -1;
android::base::unique_fd output_fd;
bool registered = false;
+ DebuggerdDumpType dump_type = kDebuggerdNativeBacktrace;
};
struct InterceptManager {
@@ -50,5 +53,5 @@
InterceptManager(InterceptManager& copy) = delete;
InterceptManager(InterceptManager&& move) = delete;
- bool GetIntercept(pid_t pid, android::base::unique_fd* out_fd);
+ bool GetIntercept(pid_t pid, DebuggerdDumpType dump_type, android::base::unique_fd* out_fd);
};
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 05df9f2..0a9f000 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -35,6 +35,7 @@
#include <cutils/sockets.h>
#include "debuggerd/handler.h"
+#include "dump_type.h"
#include "protocol.h"
#include "util.h"
@@ -52,10 +53,10 @@
struct Crash;
-class CrashType {
+class CrashQueue {
public:
- CrashType(const std::string& dir_path, const std::string& file_name_prefix, size_t max_artifacts,
- size_t max_concurrent_dumps)
+ CrashQueue(const std::string& dir_path, const std::string& file_name_prefix, size_t max_artifacts,
+ size_t max_concurrent_dumps)
: file_name_prefix_(file_name_prefix),
dir_path_(dir_path),
dir_fd_(open(dir_path.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)),
@@ -114,8 +115,8 @@
void on_crash_completed() { --num_concurrent_dumps_; }
- static CrashType* const tombstone;
- static CrashType* const java_trace;
+ static CrashQueue* const tombstone;
+ static CrashQueue* const java_trace;
private:
void find_oldest_artifact() {
@@ -158,19 +159,19 @@
std::deque<Crash*> queued_requests_;
- DISALLOW_COPY_AND_ASSIGN(CrashType);
+ DISALLOW_COPY_AND_ASSIGN(CrashQueue);
};
// Whether java trace dumps are produced via tombstoned.
static constexpr bool kJavaTraceDumpsEnabled = false;
-/* static */ CrashType* const CrashType::tombstone =
- new CrashType("/data/tombstones", "tombstone_" /* file_name_prefix */, 10 /* max_artifacts */,
- 1 /* max_concurrent_dumps */);
+/* static */ CrashQueue* const CrashQueue::tombstone =
+ new CrashQueue("/data/tombstones", "tombstone_" /* file_name_prefix */, 10 /* max_artifacts */,
+ 1 /* max_concurrent_dumps */);
-/* static */ CrashType* const CrashType::java_trace =
- (kJavaTraceDumpsEnabled ? new CrashType("/data/anr", "anr_" /* file_name_prefix */,
- 64 /* max_artifacts */, 4 /* max_concurrent_dumps */)
+/* static */ CrashQueue* const CrashQueue::java_trace =
+ (kJavaTraceDumpsEnabled ? new CrashQueue("/data/anr", "anr_" /* file_name_prefix */,
+ 64 /* max_artifacts */, 4 /* max_concurrent_dumps */)
: nullptr);
// Ownership of Crash is a bit messy.
@@ -183,10 +184,17 @@
pid_t crash_pid;
event* crash_event = nullptr;
- // Not owned by |Crash|.
- CrashType* crash_type = nullptr;
+ DebuggerdDumpType crash_type;
};
+static CrashQueue* get_crash_queue(const Crash* crash) {
+ if (crash->crash_type == kDebuggerdJavaBacktrace) {
+ return CrashQueue::java_trace;
+ }
+
+ return CrashQueue::tombstone;
+}
+
// Forward declare the callbacks so they can be placed in a sensible order.
static void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int, void*);
static void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg);
@@ -194,10 +202,8 @@
static void perform_request(Crash* crash) {
unique_fd output_fd;
- // Note that java traces are not interceptible.
- if ((crash->crash_type == CrashType::java_trace) ||
- !intercept_manager->GetIntercept(crash->crash_pid, &output_fd)) {
- output_fd = crash->crash_type->get_output_fd();
+ if (!intercept_manager->GetIntercept(crash->crash_pid, crash->crash_type, &output_fd)) {
+ output_fd = get_crash_queue(crash)->get_output_fd();
}
TombstonedCrashPacket response = {
@@ -220,7 +226,7 @@
event_add(crash->crash_event, &timeout);
}
- crash->crash_type->on_crash_started();
+ get_crash_queue(crash)->on_crash_started();
return;
fail:
@@ -228,22 +234,22 @@
}
static void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int,
- void* crash_type) {
+ void*) {
event_base* base = evconnlistener_get_base(listener);
Crash* crash = new Crash();
+ // TODO: Make sure that only java crashes come in on the java socket
+ // and only native crashes on the native socket.
struct timeval timeout = { 1, 0 };
event* crash_event = event_new(base, sockfd, EV_TIMEOUT | EV_READ, crash_request_cb, crash);
crash->crash_fd.reset(sockfd);
crash->crash_event = crash_event;
- crash->crash_type = static_cast<CrashType*>(crash_type);
event_add(crash_event, &timeout);
}
static void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg) {
ssize_t rc;
Crash* crash = static_cast<Crash*>(arg);
- CrashType* type = crash->crash_type;
TombstonedCrashPacket request = {};
@@ -271,7 +277,13 @@
goto fail;
}
- if (type == CrashType::tombstone) {
+ crash->crash_type = request.packet.dump_request.dump_type;
+ if (crash->crash_type < 0 || crash->crash_type > kDebuggerdAnyIntercept) {
+ LOG(WARNING) << "unexpected crash dump type: " << crash->crash_type;
+ goto fail;
+ }
+
+ if (crash->crash_type != kDebuggerdJavaBacktrace) {
crash->crash_pid = request.packet.dump_request.pid;
} else {
// Requests for java traces are sent from untrusted processes, so we
@@ -290,7 +302,7 @@
LOG(INFO) << "received crash request for pid " << crash->crash_pid;
- if (type->maybe_enqueue_crash(crash)) {
+ if (get_crash_queue(crash)->maybe_enqueue_crash(crash)) {
LOG(INFO) << "enqueueing crash request for pid " << crash->crash_pid;
} else {
perform_request(crash);
@@ -307,7 +319,7 @@
Crash* crash = static_cast<Crash*>(arg);
TombstonedCrashPacket request = {};
- crash->crash_type->on_crash_completed();
+ get_crash_queue(crash)->on_crash_completed();
if ((ev & EV_READ) == 0) {
goto fail;
@@ -330,11 +342,11 @@
}
fail:
- CrashType* type = crash->crash_type;
+ CrashQueue* queue = get_crash_queue(crash);
delete crash;
// If there's something queued up, let them proceed.
- type->maybe_dequeue_crashes(perform_request);
+ queue->maybe_dequeue_crashes(perform_request);
}
int main(int, char* []) {
@@ -366,7 +378,7 @@
intercept_manager = new InterceptManager(base, intercept_socket);
evconnlistener* tombstone_listener = evconnlistener_new(
- base, crash_accept_cb, CrashType::tombstone, -1, LEV_OPT_CLOSE_ON_FREE, crash_socket);
+ base, crash_accept_cb, CrashQueue::tombstone, -1, LEV_OPT_CLOSE_ON_FREE, crash_socket);
if (!tombstone_listener) {
LOG(FATAL) << "failed to create evconnlistener for tombstones.";
}
@@ -379,7 +391,7 @@
evutil_make_socket_nonblocking(java_trace_socket);
evconnlistener* java_trace_listener = evconnlistener_new(
- base, crash_accept_cb, CrashType::java_trace, -1, LEV_OPT_CLOSE_ON_FREE, java_trace_socket);
+ base, crash_accept_cb, CrashQueue::java_trace, -1, LEV_OPT_CLOSE_ON_FREE, java_trace_socket);
if (!java_trace_listener) {
LOG(FATAL) << "failed to create evconnlistener for java traces.";
}
diff --git a/debuggerd/tombstoned/tombstoned_client.cpp b/debuggerd/tombstoned/tombstoned_client.cpp
index 39dc6eb..bdb4c1a 100644
--- a/debuggerd/tombstoned/tombstoned_client.cpp
+++ b/debuggerd/tombstoned/tombstoned_client.cpp
@@ -31,10 +31,11 @@
using android::base::unique_fd;
bool tombstoned_connect(pid_t pid, unique_fd* tombstoned_socket, unique_fd* output_fd,
- bool is_native_crash) {
- unique_fd sockfd(socket_local_client(
- (is_native_crash ? kTombstonedCrashSocketName : kTombstonedJavaTraceSocketName),
- ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
+ DebuggerdDumpType dump_type) {
+ unique_fd sockfd(
+ socket_local_client((dump_type != kDebuggerdJavaBacktrace ? kTombstonedCrashSocketName
+ : kTombstonedJavaTraceSocketName),
+ ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
if (sockfd == -1) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to connect to tombstoned: %s",
strerror(errno));
@@ -44,6 +45,7 @@
TombstonedCrashPacket packet = {};
packet.packet_type = CrashPacketType::kDumpRequest;
packet.packet.dump_request.pid = pid;
+ packet.packet.dump_request.dump_type = dump_type;
if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to write DumpRequest packet: %s",
strerror(errno));
diff --git a/demangle/Android.mk b/demangle/Android.mk
new file mode 100644
index 0000000..e3cfc2a
--- /dev/null
+++ b/demangle/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2017 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := demangle_fuzzer
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := \
+ Demangler.cpp \
+ demangle_fuzzer.cpp \
+
+LOCAL_CFLAGS := \
+ -Wall \
+ -Werror \
+ -Wextra \
+
+include $(BUILD_FUZZ_TEST)
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
index fb68119..5e17362 100644
--- a/demangle/DemangleTest.cpp
+++ b/demangle/DemangleTest.cpp
@@ -22,7 +22,14 @@
#include "Demangler.h"
-TEST(DemangleTest, VoidArgumentTest) {
+TEST(DemangleTest, IllegalArgumentModifiers) {
+ Demangler demangler;
+
+ ASSERT_EQ("_Zpp4FUNKK", demangler.Parse("_Zpp4FUNKK"));
+ ASSERT_EQ("_Zpp4FUNVV", demangler.Parse("_Zpp4FUNVV"));
+}
+
+TEST(DemangleTest, VoidArgument) {
Demangler demangler;
ASSERT_EQ("func()", demangler.Parse("_ZN4funcEv"));
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
index 77cfd3b..1b7406d 100644
--- a/demangle/Demangler.cpp
+++ b/demangle/Demangler.cpp
@@ -542,9 +542,8 @@
} else {
suffix = " volatile";
}
- if (name[-1] == 'K' || name[-1] == 'V') {
+ if (!cur_state_.suffixes.empty() && (name[-1] == 'K' || name[-1] == 'V')) {
// Special case, const/volatile apply as a single entity.
- assert(!cur_state_.suffixes.empty());
size_t index = cur_state_.suffixes.size();
cur_state_.suffixes[index-1].insert(0, suffix);
} else {
@@ -723,7 +722,8 @@
&& static_cast<size_t>(cur_name - name) < max_length) {
cur_name = (this->*parse_func_)(cur_name);
}
- if (cur_name == nullptr || *cur_name != '\0' || function_name_.empty()) {
+ if (cur_name == nullptr || *cur_name != '\0' || function_name_.empty() ||
+ !cur_state_.suffixes.empty()) {
return name;
}
diff --git a/demangle/demangle_fuzzer.cpp b/demangle/demangle_fuzzer.cpp
new file mode 100644
index 0000000..83fafc2
--- /dev/null
+++ b/demangle/demangle_fuzzer.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 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 <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+
+#include "Demangler.h"
+
+extern "C" void LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ std::vector<char> data_str(size + 1);
+ memcpy(data_str.data(), data, size);
+ data_str[size] = '\0';
+
+ Demangler demangler;
+ std::string demangled_name = demangler.Parse(data_str.data());
+ if (size != 0 && data_str[0] != '\0' && demangled_name.empty()) {
+ abort();
+ }
+}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 3e890c7..271ca95 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -53,6 +53,7 @@
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
#include <sparse/sparse.h>
#include <ziparchive/zip_archive.h>
@@ -1350,7 +1351,8 @@
struct fastboot_buffer buf;
const char* errMsg = nullptr;
const struct fs_generator* gen = nullptr;
- int fd;
+ TemporaryFile output;
+ unique_fd fd;
unsigned int limit = INT_MAX;
if (target_sparse_limit > 0 && target_sparse_limit < limit) {
@@ -1403,22 +1405,23 @@
return;
}
- fd = make_temporary_fd();
- if (fd == -1) return;
-
unsigned eraseBlkSize, logicalBlkSize;
eraseBlkSize = fb_get_flash_block_size(transport, "erase-block-size");
logicalBlkSize = fb_get_flash_block_size(transport, "logical-block-size");
- if (fs_generator_generate(gen, fd, size, initial_dir, eraseBlkSize, logicalBlkSize)) {
+ if (fs_generator_generate(gen, output.path, size, initial_dir,
+ eraseBlkSize, logicalBlkSize)) {
fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
- close(fd);
return;
}
- if (!load_buf_fd(transport, fd, &buf)) {
+ fd.reset(open(output.path, O_RDONLY));
+ if (fd == -1) {
+ fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno));
+ return;
+ }
+ if (!load_buf_fd(transport, fd.release(), &buf)) {
fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
- close(fd);
return;
}
flash_buf(partition, &buf);
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 5d9ccfe..99ca7dd 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -4,6 +4,7 @@
#include "make_f2fs.h"
#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -11,12 +12,20 @@
#include <sys/types.h>
#include <unistd.h>
+#include <android-base/unique_fd.h>
#include <ext4_utils/make_ext4fs.h>
#include <sparse/sparse.h>
-static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir,
+using android::base::unique_fd;
+
+static int generate_ext4_image(const char* fileName, long long partSize, const std::string& initial_dir,
unsigned eraseBlkSize, unsigned logicalBlkSize)
{
+ unique_fd fd(open(fileName, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
+ if (fd == -1) {
+ fprintf(stderr, "Unable to open output file for EXT4 filesystem: %s\n", strerror(errno));
+ return -1;
+ }
if (initial_dir.empty()) {
make_ext4fs_sparse_fd_align(fd, partSize, NULL, NULL, eraseBlkSize, logicalBlkSize);
} else {
@@ -27,11 +36,16 @@
}
#ifdef USE_F2FS
-static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir,
+static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
unsigned /* unused */, unsigned /* unused */)
{
if (!initial_dir.empty()) {
- fprintf(stderr, "Unable to set initial directory on F2FS filesystem\n");
+ fprintf(stderr, "Unable to set initial directory on F2FS filesystem: %s\n", strerror(errno));
+ return -1;
+ }
+ unique_fd fd(open(fileName, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
+ if (fd == -1) {
+ fprintf(stderr, "Unable to open output file for F2FS filesystem: %s\n", strerror(errno));
return -1;
}
return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
@@ -42,7 +56,7 @@
const char* fs_type; //must match what fastboot reports for partition type
//returns 0 or error value
- int (*generate)(int fd, long long partSize, const std::string& initial_dir,
+ int (*generate)(const char* fileName, long long partSize, const std::string& initial_dir,
unsigned eraseBlkSize, unsigned logicalBlkSize);
} generators[] = {
@@ -61,8 +75,8 @@
return nullptr;
}
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+int fs_generator_generate(const struct fs_generator* gen, const char* fileName, long long partSize,
const std::string& initial_dir, unsigned eraseBlkSize, unsigned logicalBlkSize)
{
- return gen->generate(tmpFileNo, partSize, initial_dir, eraseBlkSize, logicalBlkSize);
+ return gen->generate(fileName, partSize, initial_dir, eraseBlkSize, logicalBlkSize);
}
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 0a5f5a4..c6baa7f 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -7,7 +7,7 @@
struct fs_generator;
const struct fs_generator* fs_get_generator(const std::string& fs_type);
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+int fs_generator_generate(const struct fs_generator* gen, const char* fileName, long long partSize,
const std::string& initial_dir, unsigned eraseBlkSize = 0, unsigned logicalBlkSize = 0);
#endif
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 73bdc7a..84981bf 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1195,7 +1195,7 @@
ret = -1;
continue;
}
- fprintf(zram_fp, "%d\n", fstab->recs[i].zram_size);
+ fprintf(zram_fp, "%u\n", fstab->recs[i].zram_size);
fclose(zram_fp);
}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index dc73c24..70cd608 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -352,6 +352,15 @@
std::vector<std::string> fstab_entry;
std::string file_name;
std::string value;
+ // skip a partition entry if the status property is present and not set to ok
+ file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
+ if (read_dt_file(file_name, &value)) {
+ if (value != "okay" && value != "ok") {
+ LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
+ continue;
+ }
+ }
+
file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 18e47e3..3490544 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -144,7 +144,7 @@
if (name[0] == '.') return false;
if (name[namelen - 1] == '.') return false;
- /* Only allow alphanumeric, plus '.', '-', '@', or '_' */
+ /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
/* Don't allow ".." to appear in a property name */
for (size_t i = 0; i < namelen; i++) {
if (name[i] == '.') {
@@ -152,7 +152,7 @@
if (name[i-1] == '.') return false;
continue;
}
- if (name[i] == '_' || name[i] == '-' || name[i] == '@') continue;
+ if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') continue;
if (name[i] >= 'a' && name[i] <= 'z') continue;
if (name[i] >= 'A' && name[i] <= 'Z') continue;
if (name[i] >= '0' && name[i] <= '9') continue;
diff --git a/libziparchive/.clang-format b/libziparchive/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libziparchive/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 0a4f088..287a99c 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -124,3 +124,29 @@
},
},
}
+
+// Performance benchmarks.
+cc_benchmark {
+ name: "ziparchive-benchmarks",
+ defaults: ["libziparchive_flags"],
+
+ srcs: [
+ "zip_archive_benchmark.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+
+ static_libs: [
+ "libziparchive",
+ "libz",
+ "libutils",
+ ],
+
+ target: {
+ host: {
+ cppflags: ["-Wno-unnamed-type-template-args"],
+ },
+ },
+}
diff --git a/libziparchive/zip_archive_benchmark.cpp b/libziparchive/zip_archive_benchmark.cpp
new file mode 100644
index 0000000..cd3e164
--- /dev/null
+++ b/libziparchive/zip_archive_benchmark.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 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 <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include <android-base/test_utils.h>
+#include <benchmark/benchmark.h>
+#include <ziparchive/zip_archive.h>
+#include <ziparchive/zip_archive_stream_entry.h>
+#include <ziparchive/zip_writer.h>
+
+static TemporaryFile* CreateZip() {
+ TemporaryFile* result = new TemporaryFile;
+ FILE* fp = fdopen(result->fd, "w");
+
+ ZipWriter writer(fp);
+ std::string lastName = "file";
+ for (size_t i = 0; i < 1000; i++) {
+ // Make file names longer and longer.
+ lastName = lastName + std::to_string(i);
+ writer.StartEntry(lastName.c_str(), ZipWriter::kCompress);
+ writer.WriteBytes("helo", 4);
+ writer.FinishEntry();
+ }
+ writer.Finish();
+ fclose(fp);
+
+ return result;
+}
+
+static void FindEntry_no_match(benchmark::State& state) {
+ // Create a temporary zip archive.
+ std::unique_ptr<TemporaryFile> temp_file(CreateZip());
+ ZipArchiveHandle handle;
+ ZipEntry data;
+
+ // In order to walk through all file names in the archive, look for a name
+ // that does not exist in the archive.
+ ZipString name("thisFileNameDoesNotExist");
+
+ // Start the benchmark.
+ while (state.KeepRunning()) {
+ OpenArchive(temp_file->path, &handle);
+ FindEntry(handle, name, &data);
+ CloseArchive(handle);
+ }
+}
+BENCHMARK(FindEntry_no_match);
+
+static void Iterate_all_files(benchmark::State& state) {
+ std::unique_ptr<TemporaryFile> temp_file(CreateZip());
+ ZipArchiveHandle handle;
+ void* iteration_cookie;
+ ZipEntry data;
+ ZipString name;
+
+ while (state.KeepRunning()) {
+ OpenArchive(temp_file->path, &handle);
+ StartIteration(handle, &iteration_cookie, nullptr, nullptr);
+ while (Next(iteration_cookie, &data, &name) == 0) {
+ }
+ EndIteration(iteration_cookie);
+ CloseArchive(handle);
+ }
+}
+BENCHMARK(Iterate_all_files);
+
+BENCHMARK_MAIN()
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index 06cc90d..07040b0 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -61,3 +61,4 @@
user logd
group log
writepid /dev/cpuset/system-background/tasks
+ oom_score_adjust -600
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 540e976..94f64e0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -7,6 +7,7 @@
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
+import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
@@ -26,6 +27,16 @@
# Set the security context of /postinstall if present.
restorecon /postinstall
+ # Mount cgroup mount point for cpu accounting
+ mount cgroup none /acct cpuacct
+ mkdir /acct/uid
+
+ # root memory control cgroup, used by lmkd
+ mkdir /dev/memcg 0700 root system
+ mount cgroup none /dev/memcg memory
+ # app mem cgroups, used by activity manager, lmkd and zygote
+ mkdir /dev/memcg/apps/ 0755 system system
+
start ueventd
on init
@@ -42,10 +53,6 @@
# Link /vendor to /system/vendor for devices without a vendor partition.
symlink /system/vendor /vendor
- # Mount cgroup mount point for cpu accounting
- mount cgroup none /acct cpuacct
- mkdir /acct/uid
-
# Create energy-aware scheduler tuning nodes
mkdir /dev/stune
mount cgroup none /dev/stune schedtune
@@ -98,12 +105,6 @@
symlink /storage/self/primary /mnt/sdcard
symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
- # root memory control cgroup, used by lmkd
- mkdir /dev/memcg 0700 root system
- mount cgroup none /dev/memcg memory
- # app mem cgroups, used by activity manager, lmkd and zygote
- mkdir /dev/memcg/apps/ 0755 system system
-
write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/kernel/hung_task_timeout_secs 0
write /proc/cpu/alignment 4