Index: chrome/app/breakpad_linuxish.cc |
diff --git a/chrome/app/breakpad_linux.cc b/chrome/app/breakpad_linuxish.cc |
similarity index 87% |
rename from chrome/app/breakpad_linux.cc |
rename to chrome/app/breakpad_linuxish.cc |
index 17b4e8ae989ac8900d55838a67be2717d5f18d23..e5c257043621d8bd38072c772dbd422149047267 100644 |
--- a/chrome/app/breakpad_linux.cc |
+++ b/chrome/app/breakpad_linuxish.cc |
@@ -6,7 +6,7 @@ |
// calls when in seccomp mode. |
#define SYS_SYSCALL_ENTRYPOINT "playground$syscallEntryPoint" |
-#include "chrome/app/breakpad_linux.h" |
+#include "chrome/app/breakpad_linuxish.h" |
#include <fcntl.h> |
#include <poll.h> |
@@ -42,7 +42,16 @@ |
#include "chrome/common/env_vars.h" |
#include "chrome/common/logging_chrome.h" |
#include "content/common/chrome_descriptors.h" |
+ |
+#if defined(OS_ANDROID) |
+#include <android/log.h> |
+#include <sys/stat.h> |
+#include "base/android/path_utils.h" |
+#include "base/android/build_info.h" |
+#include "third_party/lss/linux_syscall_support.h" |
+#else |
#include "seccompsandbox/linux_syscall_support.h" |
+#endif |
#ifndef PR_SET_PTRACER |
#define PR_SET_PTRACER 0x59616d61 |
@@ -118,6 +127,35 @@ static void my_uint64tos(char* output, uint64_t i, unsigned i_len) { |
output[index - 1] = '0' + (i % 10); |
} |
+#if defind(OS_ANDROID) |
+static char* my_strncpy(char* dst, const char* src, size_t len) { |
+ int i = len; |
+ char* p = dst; |
+ if (!dst || !src) |
+ return dst; |
+ while (i != 0 && *src != '\0') { |
+ *p++ = *src++; |
+ i--; |
+ } |
+ while (i != 0) { |
+ *p++ = '\0'; |
+ i--; |
+ } |
+ return dst; |
+} |
+ |
+static char* my_strncat(char *dest, const char *src, size_t len) { |
+ char *ret = dest; |
+ while (*dest) |
+ dest++; |
+ while (len--) |
+ if (!(*dest++ = *src++)) |
+ return ret; |
+ *dest = 0; |
+ return ret; |
+} |
+#endif |
+ |
namespace { |
// MIME substrings. |
@@ -305,6 +343,14 @@ void DumpProcess() { |
g_breakpad->WriteMinidump(); |
} |
+size_t log(const char* buf, size_t nbytes) { |
+#if defined(OS_ANDROID) |
+ return __android_log_write(ANDROID_LOG_WARN, "google-breakpad", buf); |
+#else |
+ return sys_write(2, buf, nbytes) |
+#endif |
+} |
+ |
} // namespace |
void HandleCrashDump(const BreakpadInfo& info) { |
@@ -314,13 +360,18 @@ void HandleCrashDump(const BreakpadInfo& info) { |
const int dumpfd = sys_open(info.filename, O_RDONLY, 0); |
if (dumpfd < 0) { |
static const char msg[] = "Cannot upload crash dump: failed to open\n"; |
- sys_write(2, msg, sizeof(msg)); |
+ log(msg, sizeof(msg)); |
return; |
} |
+#if defined(OS_ANDROID) |
+ struct stat st; |
+ if (fstat(dumpfd, &st) != 0) { |
+#else |
struct kernel_stat st; |
if (sys_fstat(dumpfd, &st) != 0) { |
+#endif |
static const char msg[] = "Cannot upload crash dump: stat failed\n"; |
- sys_write(2, msg, sizeof(msg)); |
+ log(msg, sizeof(msg)); |
IGNORE_RET(sys_close(dumpfd)); |
return; |
} |
@@ -330,7 +381,7 @@ void HandleCrashDump(const BreakpadInfo& info) { |
uint8_t* dump_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size)); |
if (!dump_data) { |
static const char msg[] = "Cannot upload crash dump: cannot alloc\n"; |
- sys_write(2, msg, sizeof(msg)); |
+ log(msg, sizeof(msg)); |
IGNORE_RET(sys_close(dumpfd)); |
return; |
} |
@@ -345,7 +396,7 @@ void HandleCrashDump(const BreakpadInfo& info) { |
if (ufd < 0) { |
static const char msg[] = "Cannot upload crash dump because /dev/urandom" |
" is missing\n"; |
- sys_write(2, msg, sizeof(msg) - 1); |
+ log(msg, sizeof(msg) - 1); |
return; |
} |
@@ -369,7 +420,7 @@ void HandleCrashDump(const BreakpadInfo& info) { |
if (temp_file_fd < 0) { |
static const char msg[] = "Failed to create temporary file in /tmp: " |
"cannot upload crash dump\n"; |
- sys_write(2, msg, sizeof(msg) - 1); |
+ log(msg, sizeof(msg) - 1); |
IGNORE_RET(sys_close(ufd)); |
return; |
} |
@@ -377,7 +428,7 @@ void HandleCrashDump(const BreakpadInfo& info) { |
temp_file_fd = sys_open(info.filename, O_WRONLY, 0600); |
if (temp_file_fd < 0) { |
static const char msg[] = "Failed to save crash dump: failed to open\n"; |
- sys_write(2, msg, sizeof(msg) - 1); |
+ log(msg, sizeof(msg) - 1); |
IGNORE_RET(sys_close(ufd)); |
return; |
} |
@@ -476,12 +527,27 @@ void HandleCrashDump(const BreakpadInfo& info) { |
MimeWriter writer(temp_file_fd, mime_boundary); |
{ |
-#if defined(OS_CHROMEOS) |
+#if defined(OS_ANDROID) |
+ static const char chrome_product_msg[] = "Chrome_Android"; |
+#elif defined(OS_CHROMEOS) |
static const char chrome_product_msg[] = "Chrome_ChromeOS"; |
#else // OS_LINUX |
static const char chrome_product_msg[] = "Chrome_Linux"; |
#endif |
+ |
+#if defined (OS_ANDROID) |
+ base::android::BuildInfo* android_build_info = |
+ base::android::BuildInfo::GetInstance(); |
+ static const char* version_msg = |
+ android_build_info->package_version_code(); |
+ static const char android_build_id[] = "android_build_id"; |
+ static const char android_build_fp[] = "android_build_fp"; |
+ static const char device[] = "device"; |
+ static const char model[] = "model"; |
+ static const char brand[] = "brand"; |
+#else |
static const char version_msg[] = PRODUCT_VERSION; |
+#endif |
writer.AddBoundary(); |
writer.AddPairString("prod", chrome_product_msg); |
@@ -490,6 +556,28 @@ void HandleCrashDump(const BreakpadInfo& info) { |
writer.AddBoundary(); |
writer.AddPairString("guid", info.guid); |
writer.AddBoundary(); |
+ if (info.pid > 0) { |
+ uint64_t pid_str_len = my_uint64_len(info.pid); |
+ char* pid_buf = reinterpret_cast<char*>(allocator.Alloc(pid_str_len)); |
+ my_uint64tos(pid_buf, info.pid, pid_str_len); |
+ writer.AddPairString("pid", pid_buf); |
+ writer.AddBoundary(); |
+ } |
+#if defined(OS_ANDROID) |
+ // Addtional MIME blocks are added for logging on Android devices. |
+ writer.AddPairString( |
+ android_build_id, android_build_info->android_build_id()); |
+ writer.AddBoundary(); |
+ writer.AddPairString( |
+ android_build_fp, android_build_info->android_build_fp()); |
+ writer.AddBoundary(); |
+ writer.AddPairString(device, android_build_info->device()); |
+ writer.AddBoundary(); |
+ writer.AddPairString(model, android_build_info->model()); |
+ writer.AddBoundary(); |
+ writer.AddPairString(brand, android_build_info->brand()); |
+ writer.AddBoundary(); |
+#endif |
writer.Flush(); |
} |
@@ -637,6 +725,36 @@ void HandleCrashDump(const BreakpadInfo& info) { |
writer.Flush(); |
IGNORE_RET(sys_close(temp_file_fd)); |
+#if defined(OS_ANDROID) |
+ uint64_t pid_str_len = my_uint64_len(info.pid); |
+ char* pid_buf = reinterpret_cast<char*>(allocator.Alloc(pid_str_len)); |
+ my_uint64tos(pid_buf, info.pid, pid_str_len); |
+ |
+ static const char* output_msg = "Output crash dump file:"; |
+ log(output_msg, my_strlen(output_msg)); |
+ int initial_filename_len = my_strln(info.filename); |
+ log(info.filename, info.filename); |
+ // -1 because we won't need the null terminator on the original filename. |
+ size_t done_filename_len = initial_filename_len -1 + pid_str_len; |
+ char* done_filename = reinterpret_cast<char*>( |
+ allocator.Alloc(done_filename_len)); |
+ // Rename the file such that the pid is the suffix in order signal to other |
+ // processes that the minidump is complete. The advantage of using the pid as |
+ // the suffix is that it is trivial to associate the minidump with the |
+ // crashed process. |
+ // Finally, note strncpy prevents null terminators from |
+ // being copied. Pad the rest with 0's. |
+ my_strncpy(done_filename, info.filename, done_filename_len); |
+ // Append the suffix a null terminator should be added. |
+ my_strncat(done_filename, pid_buf, pid_str_len); |
+ // Rename the minidump file to signal that it is complete. |
+ if (rename(info.filename, done_filename)) { |
+ __android_log_write(ANDROID_LOG_WARN, "chromium", "Failed to rename:"); |
+ __android_log_write(ANDROID_LOG_WARN, "chromium", info.filename); |
+ __android_log_write(ANDROID_LOG_WARN, "chromium", "to"); |
+ __android_log_write(ANDROID_LOG_WARN, "chromium", done_filename); |
+ } |
+#endif |
if (!info.upload) |
return; |
@@ -718,7 +836,7 @@ void HandleCrashDump(const BreakpadInfo& info) { |
execve(kWgetBinary, const_cast<char**>(args), environ); |
static const char msg[] = "Cannot upload crash dump: cannot exec " |
"/usr/bin/wget\n"; |
- sys_write(2, msg, sizeof(msg) - 1); |
+ log(msg, sizeof(msg) - 1); |
sys__exit(1); |
} |
@@ -748,9 +866,9 @@ void HandleCrashDump(const BreakpadInfo& info) { |
// Write crash dump id to stderr. |
id_buf[len] = 0; |
static const char msg[] = "\nCrash dump id: "; |
- sys_write(2, msg, sizeof(msg) - 1); |
- sys_write(2, id_buf, my_strlen(id_buf)); |
- sys_write(2, "\n", 1); |
+ log(msg, sizeof(msg) - 1); |
+ log(id_buf, my_strlen(id_buf)); |
+ log("\n", 1); |
// Write crash dump id to crash log as: seconds_since_epoch,crash_id |
struct kernel_timeval tv; |
@@ -825,6 +943,7 @@ static bool CrashDone(const char* dump_path, |
info.upload = upload; |
info.process_start_time = g_process_start_time; |
info.oom_size = base::g_oom_size; |
+ info.pid = 0; |
HandleCrashDump(info); |
return true; |
} |
@@ -837,6 +956,7 @@ static bool CrashDoneNoUpload(const char* dump_path, |
return CrashDone(dump_path, minidump_id, false, succeeded); |
} |
+#if !defined(OS_ANDROID) |
// Wrapper function, do not add more code here. |
static bool CrashDoneUpload(const char* dump_path, |
const char* minidump_id, |
@@ -844,6 +964,7 @@ static bool CrashDoneUpload(const char* dump_path, |
bool succeeded) { |
return CrashDone(dump_path, minidump_id, true, succeeded); |
} |
+#endif |
void EnableCrashDumping(const bool unattended) { |
g_is_crash_reporter_enabled = true; |
@@ -860,8 +981,16 @@ void EnableCrashDumping(const bool unattended) { |
g_crash_log_path = new char[crash_log_path_len]; |
strncpy(g_crash_log_path, logfile_str.c_str(), crash_log_path_len); |
} |
- |
DCHECK(!g_breakpad); |
+#if defined(OS_ANDROID) |
+ // In Android we never upload from native code. |
+ g_breakpad = new google_breakpad::ExceptionHandler( |
+ dumps_path.value().c_str(), |
+ NULL, |
+ CrashDoneNoUpload, |
+ NULL, |
+ true /* install handlers */); |
+#else |
if (unattended) { |
g_breakpad = new google_breakpad::ExceptionHandler( |
dumps_path.value().c_str(), |
@@ -877,6 +1006,7 @@ void EnableCrashDumping(const bool unattended) { |
NULL, |
true /* install handlers */); |
} |
+#endif |
} |
// Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer |
@@ -887,7 +1017,7 @@ static bool NonBrowserCrashHandler(const void* crash_context, |
int fds[2] = { -1, -1 }; |
if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { |
static const char msg[] = "Failed to create socket for crash dumping.\n"; |
- sys_write(2, msg, sizeof(msg)-1); |
+ log(msg, sizeof(msg)-1); |
return false; |
} |
@@ -964,7 +1094,7 @@ static bool NonBrowserCrashHandler(const void* crash_context, |
if (HANDLE_EINTR(sys_sendmsg(fd, &msg, 0)) < 0) { |
static const char errmsg[] = "Failed to tell parent about crash.\n"; |
- sys_write(2, errmsg, sizeof(errmsg)-1); |
+ log(errmsg, sizeof(errmsg)-1); |
IGNORE_RET(sys_close(fds[1])); |
return false; |
} |
@@ -972,7 +1102,7 @@ static bool NonBrowserCrashHandler(const void* crash_context, |
if (HANDLE_EINTR(sys_read(fds[0], &b, 1)) != 1) { |
static const char errmsg[] = "Parent failed to complete crash dump.\n"; |
- sys_write(2, errmsg, sizeof(errmsg)-1); |
+ log(errmsg, sizeof(errmsg)-1); |
} |
return true; |
@@ -989,6 +1119,11 @@ void EnableNonBrowserCrashDumping() { |
} |
void InitCrashReporter() { |
+#if defined(OS_ANDROID) |
+ // This will guarantee that the BuildInfo has been initialized and subsequent |
+ // calls will not require memory allocation. |
+ base::android::BuildInfo::GetInstance(); |
+#endif |
// Determine the process type and take appropriate action. |
const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
if (parsed_command_line.HasSwitch(switches::kDisableBreakpad)) |
@@ -1003,6 +1138,9 @@ void InitCrashReporter() { |
process_type == switches::kPpapiPluginProcess || |
process_type == switches::kZygoteProcess || |
process_type == switches::kGpuProcess) { |
+#if defined(OS_ANDROID) |
+ child_process_logging::SetClientId("Android"); |
+#endif |
// We might be chrooted in a zygote or renderer process so we cannot call |
// GetCollectStatsConsent because that needs access the the user's home |
// dir. Instead, we set a command line flag for these processes. |