| Index: src/platform/crash/crash_sender
|
| diff --git a/src/platform/crash/crash_sender b/src/platform/crash/crash_sender
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d72cbfba291db1dadc19f6fd38c4923517cbfd0f
|
| --- /dev/null
|
| +++ b/src/platform/crash/crash_sender
|
| @@ -0,0 +1,198 @@
|
| +#!/bin/sh
|
| +
|
| +# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +set -e
|
| +
|
| +# Product ID in crash report
|
| +CHROMEOS_PRODUCT=ChromeOS
|
| +
|
| +# Send up to 8 crashes per day.
|
| +MAX_CRASH_RATE=8
|
| +
|
| +# Minidump uploading tool (provided by Google Breakpad).
|
| +MINIDUMP_UPLOADER=/usr/bin/minidump_upload
|
| +
|
| +# URL to send non-official build crashes to.
|
| +MINIDUMP_UPLOAD_STAGING_URL="http://clients2.google.com/cr/staging_report"
|
| +
|
| +# URL to send official build crashes to.
|
| +MINIDUMP_UPLOAD_PROD_URL="http://clients2.google.com/cr/report"
|
| +
|
| +# File whose existence mocks crash sending. If empty we pretend the
|
| +# crash sending was successful, otherwise unsuccessful.
|
| +MOCK_CRASH_SENDING="/tmp/mock-crash-sending"
|
| +
|
| +# File whose existence causes crash sending to be delayed (for testing).
|
| +PAUSE_CRASH_SENDING="/tmp/pause-crash-sending"
|
| +
|
| +# File whose existence implies we're running and not to start again.
|
| +RUN_FILE="/var/run/crash_sender.pid"
|
| +
|
| +# Maximum time to sleep between sends.
|
| +SECONDS_SEND_SPREAD=3600
|
| +
|
| +# The syslog tag for all logging we emit.
|
| +TAG="$(basename $0)[$$]"
|
| +
|
| +# Directory to store timestamp files indicating the uploads in the past 24
|
| +# hours.
|
| +TIMESTAMPS_DIR="/var/lib/crash_sender"
|
| +
|
| +lecho() {
|
| + logger -t "${TAG}" "$@"
|
| +}
|
| +
|
| +remove_run_file() {
|
| + rm -f "${RUN_FILE}"
|
| +}
|
| +
|
| +check_not_already_running() {
|
| + if [ ! -f "${RUN_FILE}" ]; then
|
| + return
|
| + fi
|
| + local last_pid=$(cat "${RUN_FILE}")
|
| + if [ ! -f "/proc/${last_pid}/cmdline" ]; then
|
| + trap remove_run_file EXIT
|
| + echo $$ > "${RUN_FILE}"
|
| + return
|
| + fi
|
| + # This could just be an unrelated process, but it's ok to be conservative.
|
| + lecho "Already running. Exiting now."
|
| + exit 1
|
| +}
|
| +
|
| +get_version() {
|
| + grep ^CHROMEOS_RELEASE_VERSION /etc/lsb-release | cut -d = -f 2-
|
| +}
|
| +
|
| +# Generate a uniform random number in 0..max-1.
|
| +generate_uniform_random() {
|
| + local max=$1
|
| + local random="$(od -An -N4 -tu /dev/urandom)"
|
| + echo $((random % max))
|
| +}
|
| +
|
| +is_feedback_disabled() {
|
| + # See crosbug.com/3303.
|
| + return 1
|
| +}
|
| +
|
| +is_on_3g() {
|
| + # See crosbug.com/3304.
|
| + return 1
|
| +}
|
| +
|
| +# Check if sending a crash now does not exceed the maximum 24hr rate and
|
| +# commit to doing so, if not.
|
| +check_rate() {
|
| + mkdir -p ${TIMESTAMPS_DIR}
|
| + # Only consider minidumps written in the past 24 hours by removing all older.
|
| + find "${TIMESTAMPS_DIR}" -mindepth 1 -mmin +$((24 * 60)) -exec rm '{}' ';'
|
| + local sends_in_24hrs=$(echo "${TIMESTAMPS_DIR}"/* | wc -w)
|
| + lecho "Current send rate: ${sends_in_24hrs}sends/24hrs"
|
| + if [ ${sends_in_24hrs} -ge ${MAX_CRASH_RATE} ]; then
|
| + lecho "Cannot send more crashes:"
|
| + lecho " current ${sends_in_24hrs}send/24hrs >= " \
|
| + "max ${MAX_CRASH_RATE}send/24hrs"
|
| + return 1
|
| + fi
|
| + mktemp "${TIMESTAMPS_DIR}"/XXXX > /dev/null
|
| + return 0
|
| +}
|
| +
|
| +send_crash() {
|
| + local sleep_time=$(generate_uniform_random $SECONDS_SEND_SPREAD)
|
| + local url="${MINIDUMP_UPLOAD_STAGING_URL}"
|
| + lecho "Sending crash:"
|
| + lecho " Scheduled to send in ${sleep_time}s"
|
| + lecho " Minidump: ${minidump_path}"
|
| + lecho " URL: ${url}"
|
| + lecho " Product: ${CHROMEOS_PRODUCT}"
|
| + lecho " Version: ${chromeos_version}"
|
| + if [ -s "${minidump_path}" ]; then
|
| + # We cannot tell much from the minidump without symbols, but we can tell
|
| + # at least what modules were loaded at the time of crash
|
| + local modules="$(/usr/bin/minidump_dump "${minidump_path}" 2>&- | \
|
| + grep 'code_file' | sed -e 's/^.* = "//g;s/"//g' | \
|
| + tr '\n' ' ')"
|
| + lecho " Mapped: ${modules}"
|
| + fi
|
| + if [ -f "${MOCK_CRASH_SENDING}" ]; then
|
| + local mock_in=$(cat "${MOCK_CRASH_SENDING}")
|
| + if [ "${mock_in}" = "" ]; then
|
| + lecho "Mocking successful send"
|
| + return 0
|
| + else
|
| + lecho "Mocking unsuccessful send"
|
| + return 1
|
| + fi
|
| + fi
|
| +
|
| + if ! sleep ${sleep_time}; then
|
| + lecho "Sleep failed"
|
| + return 1
|
| + fi
|
| +
|
| + "${MINIDUMP_UPLOADER}" -p "${CHROMEOS_PRODUCT}" \
|
| + -v "${chromeos_version}" "${minidump_path}" "${url}"
|
| + return $?
|
| +}
|
| +
|
| +# Send all crashes from the given directory. The directory is currently
|
| +# expected to just contain a bunch of minidumps - but this will change
|
| +# over time to be a directory of directories where the minidump and core
|
| +# file are in the directory as well as other metadata about the context
|
| +# of the crash (executable name for instance).
|
| +send_crashes() {
|
| + local dir="$1"
|
| + lecho "Considering crashes in ${dir}"
|
| + # Cycle through minidumps, most recent first. That way if we're about
|
| + # to exceed the daily rate, we send the most recent minidumps.
|
| + if [ ! -d "${dir}" ]; then
|
| + return
|
| + fi
|
| + for file in $(ls -1t "${dir}"); do
|
| + local minidump_path="${dir}/${file}"
|
| + lecho "Considering crash ${minidump_path}"
|
| + if ! check_rate; then
|
| + lecho "Sending ${minidump_path} would exceed rate. Leaving for later."
|
| + return 0
|
| + fi
|
| + local chromeos_version=$(get_version)
|
| + if is_feedback_disabled; then
|
| + lecho "Uploading is disabled. Removing crash."
|
| + rm "${minidump_path}"
|
| + elif is_on_3g; then
|
| + lecho "Not sending crash report while on 3G, saving for later."
|
| + elif send_crash ${minidump_path}; then
|
| + # Send was successful, now remove
|
| + lecho "Successfully sent crash ${minidump_path} and removing"
|
| + rm "${minidump_path}"
|
| + else
|
| + lecho "Problem sending ${minidump_path}, not removing"
|
| + fi
|
| + done
|
| +}
|
| +
|
| +main() {
|
| + lecho "Starting"
|
| + if [ -e "${PAUSE_CRASH_SENDING}" ]; then
|
| + lecho "Exiting early due to ${PAUSE_CRASH_SENDING}"
|
| + exit 1
|
| + fi
|
| +
|
| + check_not_already_running
|
| +
|
| + # Send system-wide crashes
|
| + send_crashes "/var/spool/crash"
|
| +
|
| + # Send user-specific crashes
|
| + send_crashes "/home/chronos/user/crash"
|
| +
|
| + lecho "Done"
|
| +}
|
| +
|
| +main
|
|
|