Index: crash_sender |
diff --git a/crash_sender b/crash_sender |
index c62f88aa460a9b2db0a306203750136ca49bb5d2..f6b3e3a58fe31a27fa66001c58b7c66b0e631ac2 100644 |
--- a/crash_sender |
+++ b/crash_sender |
@@ -21,8 +21,15 @@ CONSENT_ID="/home/chronos/Consent To Send Stats" |
# Path to find which is required for computing the crash rate. |
FIND="/usr/bin/find" |
+# Set this to 1 in the environment to allow uploading crash reports |
+# for unofficial versions. |
+FORCE_OFFICIAL=${FORCE_OFFICIAL:-0} |
+ |
+# Path to hardware class description. |
+HWCLASS_PATH="/sys/devices/platform/chromeos_acpi/HWID" |
+ |
# Maximum crashes to send per day. |
-MAX_CRASH_RATE=32 |
+MAX_CRASH_RATE=${MAX_CRASH_RATE:-32} |
# File whose existence mocks crash sending. If empty we pretend the |
# crash sending was successful, otherwise unsuccessful. |
@@ -32,9 +39,6 @@ MOCK_CRASH_SENDING="/tmp/mock-crash-sending" |
# Must be stateful to enable testing kernel crashes. |
PAUSE_CRASH_SENDING="/var/lib/crash_sender_paused" |
-# URL to send non-official build crash reports to. |
-REPORT_UPLOAD_STAGING_URL="http://clients2.google.com/cr/staging_report" |
- |
# URL to send official build crash reports to. |
REPORT_UPLOAD_PROD_URL="http://clients2.google.com/cr/report" |
@@ -89,11 +93,8 @@ check_not_already_running() { |
exit 1 |
} |
-get_version() { |
- grep ^CHROMEOS_RELEASE_VERSION /etc/lsb-release | cut -d = -f 2- |
-} |
- |
is_official() { |
+ [ ${FORCE_OFFICIAL} -ne 0 ] && return 0 |
grep ^CHROMEOS_RELEASE_DESCRIPTION /etc/lsb-release | grep -q Official |
} |
@@ -119,7 +120,8 @@ is_on_3g() { |
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 '{}' ';' |
+ ${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 |
@@ -132,37 +134,81 @@ check_rate() { |
return 0 |
} |
-# Return if $1 is a .core file |
+# Gets the base part of a crash report file, such as |
+# name.01234.5678.9012 from name.01234.5678.9012.meta |
+get_base() { |
+ echo "${1%.*}" |
+} |
+ |
+# Return which kind of report the given metadata file relates to |
get_kind() { |
- local kind="${1##*.}" |
- if [ "${kind}" = "dmp" ]; then |
- kind="minidump" |
+ # There should never be a report with both a dmp and kcrash file. |
+ # If that were to happen we arbitrarily consider this a minidump |
+ # report and effectively ignore the kcrash. |
+ local base="$(get_base "$1")" |
+ if [ -r "${base}.dmp" ]; then |
+ echo "minidump" |
+ return |
+ fi |
+ if [ -r "${base}.kcrash" ]; then |
+ echo "kcrash" |
+ return |
+ fi |
+} |
+ |
+get_key_value() { |
+ if ! grep -q "$2=" "$1"; then |
+ echo "undefined" |
+ return |
fi |
- echo ${kind} |
+ grep "$2=" "$1" | cut -d = -f 2- |
+} |
+ |
+# Returns true if mock is enabled. |
+is_mock() { |
+ [ -f "${MOCK_CRASH_SENDING}" ] && return 0 |
+ return 1 |
} |
-get_exec_name() { |
- local filename=$(basename "$1") |
- echo "${filename%%.*}" |
+# Return the board name. |
+get_board() { |
+ echo $(get_key_value "/etc/lsb-release" "CHROMEOS_RELEASE_BOARD") |
+} |
+ |
+# Return the hardware class or "unknown". |
+get_hardware_class() { |
+ if [ -r "${HWCLASS_PATH}" ]; then |
+ cat "${HWCLASS_PATH}" |
+ else |
+ echo "unknown" |
+ fi |
} |
send_crash() { |
- local report_path="$1" |
- local kind=$(get_kind "${report_path}") |
- local exec_name=$(get_exec_name "${report_path}") |
+ local meta_path="$1" |
+ local kind="$(get_kind "${meta_path}")" |
+ local exec_name="$(get_key_value "${meta_path}" "exec_name")" |
local sleep_time=$(generate_uniform_random $SECONDS_SEND_SPREAD) |
- local url="${REPORT_UPLOAD_STAGING_URL}" |
- if is_official; then |
- url="${REPORT_UPLOAD_PROD_URL}" |
- fi |
+ local url="${REPORT_UPLOAD_PROD_URL}" |
+ local chromeos_version="$(get_key_value "${meta_path}" "ver")" |
+ local board="$(get_board)" |
+ local hwclass="$(get_hardware_class)" |
+ local payload_extension="${kind}" |
+ [ "${kind}" = "minidump" ] && payload_extension="dmp" |
+ local report_payload="$(get_base "${meta_path}").${payload_extension}" |
lecho "Sending crash:" |
lecho " Scheduled to send in ${sleep_time}s" |
- lecho " Report: ${report_path} (${kind})" |
- lecho " URL: ${url}" |
- lecho " Product: ${CHROMEOS_PRODUCT}" |
+ lecho " Metadata: ${meta_path} (${kind})" |
+ lecho " Payload: ${report_payload}" |
lecho " Version: ${chromeos_version}" |
+ if is_mock; then |
+ lecho " Product: ${CHROMEOS_PRODUCT}" |
+ lecho " URL: ${url}" |
+ lecho " Board: ${board}" |
+ lecho " HWClass: ${hwclass}" |
+ fi |
lecho " Exec name: ${exec_name}" |
- if [ -f "${MOCK_CRASH_SENDING}" ]; then |
+ if is_mock; then |
local mock_in=$(cat "${MOCK_CRASH_SENDING}") |
if [ "${mock_in}" = "" ]; then |
lecho "Mocking successful send" |
@@ -185,7 +231,9 @@ send_crash() { |
curl "${url}" \ |
-F "prod=${CHROMEOS_PRODUCT}" \ |
-F "ver=${chromeos_version}" \ |
- -F "upload_file_${kind}=@${report_path}" \ |
+ -F "upload_file_${kind}=@${report_payload}" \ |
+ -F "board=${board}" \ |
+ -F "hwclass=${hwclass}" \ |
-F "exec_name=${exec_name}" \ |
-F "guid=<${CONSENT_ID}" -o "${report_id}" 2>"${curl_stderr}" |
curl_result=$? |
@@ -202,53 +250,98 @@ send_crash() { |
return ${curl_result} |
} |
+# *.meta files always end with done=1 so we can tell if they are complete. |
+is_complete_metadata() { |
+ grep -q "done=1" "$1" |
+} |
+ |
+# Remove the given report path. |
+remove_report() { |
+ local base="${1%.*}" |
+ rm -f -- "${base}".* |
+} |
+ |
# Send all crashes from the given directory. |
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 report_path="${dir}/${file}" |
- lecho "Considering file ${report_path}" |
- local kind=$(get_kind "${report_path}") |
- if [ "${kind}" = "core" ]; then |
- lecho "Ignoring core file." |
+ # Consider any old files which still have no corresponding meta file |
+ # as orphaned, and remove them. |
+ for old_file in $(${FIND} "${dir}" -mindepth 1 \ |
+ -mmin +$((24 * 60)) -type f); do |
+ if [ ! -e "$(get_base "${old_file}").meta" ]; then |
+ lecho "Removing old orphaned file: ${old_file}." |
+ rm -f -- "${old_file}" |
+ fi |
+ done |
+ |
+ # Look through all metadata (*.meta) files, if any exist. |
+ for meta_path in $(ls -1t "${dir}"/*.meta 2>/dev/null); do |
+ lecho "Considering metadata ${meta_path}." |
+ local kind=$(get_kind "${meta_path}") |
+ |
+ if [ "${kind}" != "minidump" ] && [ "${kind}" != "kcrash" ]; then |
+ lecho "Unknown report kind. Removing report." |
+ remove_report "${meta_path}" |
continue |
- elif [ "${kind}" != "minidump" ] && [ "${kind}" != "kcrash" ]; then |
- lecho "Unknown report kind: ${kind}. Removing report." |
- rm -f "${report_path}" |
+ fi |
+ |
+ if is_feedback_disabled; then |
+ lecho "Uploading is disabled. Removing crash." |
+ remove_report "${meta_path}" |
+ continue |
+ fi |
+ |
+ if ! is_mock && ! is_official; then |
+ lecho "Not an official OS version. Removing crash." |
+ remove_report "${meta_path}" |
continue |
fi |
+ |
+ if is_on_3g; then |
+ lecho "Not sending crash reports while on 3G, saving for later." |
+ return 0 |
+ fi |
+ |
+ if ! is_complete_metadata "${meta_path}"; then |
+ # This report is incomplete, so if it's old, just remove it. |
+ local old_meta=$(${FIND} "${dir}" -mindepth 1 -name \ |
+ $(basename "${meta_path}") -mmin +$((24 * 60)) -type f) |
+ if [ -n "${old_meta}" ]; then |
+ lecho "Removing old incomplete metadata." |
+ remove_report "${meta_path}" |
+ else |
+ lecho "Ignoring recent incomplete metadata." |
+ fi |
+ continue |
+ fi |
+ |
if ! check_rate; then |
- lecho "Sending ${report_path} would exceed rate. Leaving for later." |
+ lecho "Sending ${meta_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 "${report_path}" |
- elif is_on_3g; then |
- lecho "Not sending crash report while on 3G, saving for later." |
- elif send_crash "${report_path}"; then |
- # Send was successful, now remove |
- lecho "Successfully sent crash ${report_path} and removing" |
- rm "${report_path}" |
- else |
- lecho "Problem sending ${report_path}, not removing" |
+ |
+ if ! send_crash "${meta_path}"; then |
+ lecho "Problem sending ${meta_path}, not removing." |
+ continue |
fi |
+ |
+ # Send was successful, now remove. |
+ lecho "Successfully sent crash ${meta_path} and removing." |
+ remove_report "${meta_path}" |
done |
} |
main() { |
trap cleanup EXIT INT TERM |
if [ -e "${PAUSE_CRASH_SENDING}" ]; then |
- lecho "Exiting early due to ${PAUSE_CRASH_SENDING}" |
+ lecho "Exiting early due to ${PAUSE_CRASH_SENDING}." |
exit 1 |
fi |