| OLD | NEW |
| 1 #!/bin/sh | 1 #!/bin/sh |
| 2 | 2 |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 set -e | 7 set -e |
| 8 | 8 |
| 9 # Product ID in crash report | 9 # Product ID in crash report |
| 10 CHROMEOS_PRODUCT=ChromeOS | 10 CHROMEOS_PRODUCT=ChromeOS |
| 11 | 11 |
| 12 # Should remove the run file when this process finishes. We don't want | 12 # Should remove the run file when this process finishes. We don't want |
| 13 # to always remove it since it may be for pre-existing crash_sender | 13 # to always remove it since it may be for pre-existing crash_sender |
| 14 # process. | 14 # process. |
| 15 CLEAN_UP_RUN_FILE=0 | 15 CLEAN_UP_RUN_FILE=0 |
| 16 | 16 |
| 17 # File whose existence implies crash reports may be sent, and whose | 17 # File whose existence implies crash reports may be sent, and whose |
| 18 # contents includes our machine's anonymized guid. | 18 # contents includes our machine's anonymized guid. |
| 19 CONSENT_ID="/home/chronos/Consent To Send Stats" | 19 CONSENT_ID="/home/chronos/Consent To Send Stats" |
| 20 | 20 |
| 21 # Path to find which is required for computing the crash rate. | 21 # Path to find which is required for computing the crash rate. |
| 22 FIND="/usr/bin/find" | 22 FIND="/usr/bin/find" |
| 23 | 23 |
| 24 # Set this to 1 in the environment to allow uploading crash reports |
| 25 # for unofficial versions. |
| 26 FORCE_OFFICIAL=${FORCE_OFFICIAL:-0} |
| 27 |
| 28 # Path to hardware class description. |
| 29 HWCLASS_PATH="/sys/devices/platform/chromeos_acpi/HWID" |
| 30 |
| 24 # Maximum crashes to send per day. | 31 # Maximum crashes to send per day. |
| 25 MAX_CRASH_RATE=32 | 32 MAX_CRASH_RATE=${MAX_CRASH_RATE:-32} |
| 26 | 33 |
| 27 # File whose existence mocks crash sending. If empty we pretend the | 34 # File whose existence mocks crash sending. If empty we pretend the |
| 28 # crash sending was successful, otherwise unsuccessful. | 35 # crash sending was successful, otherwise unsuccessful. |
| 29 MOCK_CRASH_SENDING="/tmp/mock-crash-sending" | 36 MOCK_CRASH_SENDING="/tmp/mock-crash-sending" |
| 30 | 37 |
| 31 # File whose existence causes crash sending to be delayed (for testing). | 38 # File whose existence causes crash sending to be delayed (for testing). |
| 32 # Must be stateful to enable testing kernel crashes. | 39 # Must be stateful to enable testing kernel crashes. |
| 33 PAUSE_CRASH_SENDING="/var/lib/crash_sender_paused" | 40 PAUSE_CRASH_SENDING="/var/lib/crash_sender_paused" |
| 34 | 41 |
| 35 # URL to send non-official build crash reports to. | |
| 36 REPORT_UPLOAD_STAGING_URL="http://clients2.google.com/cr/staging_report" | |
| 37 | |
| 38 # URL to send official build crash reports to. | 42 # URL to send official build crash reports to. |
| 39 REPORT_UPLOAD_PROD_URL="http://clients2.google.com/cr/report" | 43 REPORT_UPLOAD_PROD_URL="http://clients2.google.com/cr/report" |
| 40 | 44 |
| 41 # File whose existence implies we're running and not to start again. | 45 # File whose existence implies we're running and not to start again. |
| 42 RUN_FILE="/var/run/crash_sender.pid" | 46 RUN_FILE="/var/run/crash_sender.pid" |
| 43 | 47 |
| 44 # Maximum time to sleep between sends. | 48 # Maximum time to sleep between sends. |
| 45 SECONDS_SEND_SPREAD=${SECONDS_SEND_SPREAD:-600} | 49 SECONDS_SEND_SPREAD=${SECONDS_SEND_SPREAD:-600} |
| 46 | 50 |
| 47 # The syslog tag for all logging we emit. | 51 # The syslog tag for all logging we emit. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 # Note that this write may be executed by two crash_senders who | 86 # Note that this write may be executed by two crash_senders who |
| 83 # simulataneously reap the existing dangling run file | 87 # simulataneously reap the existing dangling run file |
| 84 echo $$ > "${RUN_FILE}" | 88 echo $$ > "${RUN_FILE}" |
| 85 return | 89 return |
| 86 fi | 90 fi |
| 87 # This could just be an unrelated process, but it's ok to be conservative. | 91 # This could just be an unrelated process, but it's ok to be conservative. |
| 88 lecho "Already running. Exiting now." | 92 lecho "Already running. Exiting now." |
| 89 exit 1 | 93 exit 1 |
| 90 } | 94 } |
| 91 | 95 |
| 92 get_version() { | |
| 93 grep ^CHROMEOS_RELEASE_VERSION /etc/lsb-release | cut -d = -f 2- | |
| 94 } | |
| 95 | |
| 96 is_official() { | 96 is_official() { |
| 97 [ ${FORCE_OFFICIAL} -ne 0 ] && return 0 |
| 97 grep ^CHROMEOS_RELEASE_DESCRIPTION /etc/lsb-release | grep -q Official | 98 grep ^CHROMEOS_RELEASE_DESCRIPTION /etc/lsb-release | grep -q Official |
| 98 } | 99 } |
| 99 | 100 |
| 100 # Generate a uniform random number in 0..max-1. | 101 # Generate a uniform random number in 0..max-1. |
| 101 generate_uniform_random() { | 102 generate_uniform_random() { |
| 102 local max=$1 | 103 local max=$1 |
| 103 local random="$(od -An -N4 -tu /dev/urandom)" | 104 local random="$(od -An -N4 -tu /dev/urandom)" |
| 104 echo $((random % max)) | 105 echo $((random % max)) |
| 105 } | 106 } |
| 106 | 107 |
| 107 is_feedback_disabled() { | 108 is_feedback_disabled() { |
| 108 [ -r "${CONSENT_ID}" ] && return 1 | 109 [ -r "${CONSENT_ID}" ] && return 1 |
| 109 return 0 | 110 return 0 |
| 110 } | 111 } |
| 111 | 112 |
| 112 is_on_3g() { | 113 is_on_3g() { |
| 113 # See crosbug.com/3304. | 114 # See crosbug.com/3304. |
| 114 return 1 | 115 return 1 |
| 115 } | 116 } |
| 116 | 117 |
| 117 # Check if sending a crash now does not exceed the maximum 24hr rate and | 118 # Check if sending a crash now does not exceed the maximum 24hr rate and |
| 118 # commit to doing so, if not. | 119 # commit to doing so, if not. |
| 119 check_rate() { | 120 check_rate() { |
| 120 mkdir -p ${TIMESTAMPS_DIR} | 121 mkdir -p ${TIMESTAMPS_DIR} |
| 121 # Only consider minidumps written in the past 24 hours by removing all older. | 122 # Only consider minidumps written in the past 24 hours by removing all older. |
| 122 ${FIND} "${TIMESTAMPS_DIR}" -mindepth 1 -mmin +$((24 * 60)) -exec rm '{}' ';' | 123 ${FIND} "${TIMESTAMPS_DIR}" -mindepth 1 -mmin +$((24 * 60)) \ |
| 124 -exec rm -- '{}' ';' |
| 123 local sends_in_24hrs=$(echo "${TIMESTAMPS_DIR}"/* | wc -w) | 125 local sends_in_24hrs=$(echo "${TIMESTAMPS_DIR}"/* | wc -w) |
| 124 lecho "Current send rate: ${sends_in_24hrs}sends/24hrs" | 126 lecho "Current send rate: ${sends_in_24hrs}sends/24hrs" |
| 125 if [ ${sends_in_24hrs} -ge ${MAX_CRASH_RATE} ]; then | 127 if [ ${sends_in_24hrs} -ge ${MAX_CRASH_RATE} ]; then |
| 126 lecho "Cannot send more crashes:" | 128 lecho "Cannot send more crashes:" |
| 127 lecho " current ${sends_in_24hrs}send/24hrs >= " \ | 129 lecho " current ${sends_in_24hrs}send/24hrs >= " \ |
| 128 "max ${MAX_CRASH_RATE}send/24hrs" | 130 "max ${MAX_CRASH_RATE}send/24hrs" |
| 129 return 1 | 131 return 1 |
| 130 fi | 132 fi |
| 131 mktemp "${TIMESTAMPS_DIR}"/XXXX > /dev/null | 133 mktemp "${TIMESTAMPS_DIR}"/XXXX > /dev/null |
| 132 return 0 | 134 return 0 |
| 133 } | 135 } |
| 134 | 136 |
| 135 # Return if $1 is a .core file | 137 # Gets the base part of a crash report file, such as |
| 136 get_kind() { | 138 # name.01234.5678.9012 from name.01234.5678.9012.meta |
| 137 local kind="${1##*.}" | 139 get_base() { |
| 138 if [ "${kind}" = "dmp" ]; then | 140 echo "${1%.*}" |
| 139 kind="minidump" | |
| 140 fi | |
| 141 echo ${kind} | |
| 142 } | 141 } |
| 143 | 142 |
| 144 get_exec_name() { | 143 # Return which kind of report the given metadata file relates to |
| 145 local filename=$(basename "$1") | 144 get_kind() { |
| 146 echo "${filename%%.*}" | 145 # There should never be a report with both a dmp and kcrash file. |
| 146 # If that were to happen we arbitrarily consider this a minidump |
| 147 # report and effectively ignore the kcrash. |
| 148 local base="$(get_base "$1")" |
| 149 if [ -r "${base}.dmp" ]; then |
| 150 echo "minidump" |
| 151 return |
| 152 fi |
| 153 if [ -r "${base}.kcrash" ]; then |
| 154 echo "kcrash" |
| 155 return |
| 156 fi |
| 157 } |
| 158 |
| 159 get_key_value() { |
| 160 if ! grep -q "$2=" "$1"; then |
| 161 echo "undefined" |
| 162 return |
| 163 fi |
| 164 grep "$2=" "$1" | cut -d = -f 2- |
| 165 } |
| 166 |
| 167 # Returns true if mock is enabled. |
| 168 is_mock() { |
| 169 [ -f "${MOCK_CRASH_SENDING}" ] && return 0 |
| 170 return 1 |
| 171 } |
| 172 |
| 173 # Return the board name. |
| 174 get_board() { |
| 175 echo $(get_key_value "/etc/lsb-release" "CHROMEOS_RELEASE_BOARD") |
| 176 } |
| 177 |
| 178 # Return the hardware class or "unknown". |
| 179 get_hardware_class() { |
| 180 if [ -r "${HWCLASS_PATH}" ]; then |
| 181 cat "${HWCLASS_PATH}" |
| 182 else |
| 183 echo "unknown" |
| 184 fi |
| 147 } | 185 } |
| 148 | 186 |
| 149 send_crash() { | 187 send_crash() { |
| 150 local report_path="$1" | 188 local meta_path="$1" |
| 151 local kind=$(get_kind "${report_path}") | 189 local kind="$(get_kind "${meta_path}")" |
| 152 local exec_name=$(get_exec_name "${report_path}") | 190 local exec_name="$(get_key_value "${meta_path}" "exec_name")" |
| 153 local sleep_time=$(generate_uniform_random $SECONDS_SEND_SPREAD) | 191 local sleep_time=$(generate_uniform_random $SECONDS_SEND_SPREAD) |
| 154 local url="${REPORT_UPLOAD_STAGING_URL}" | 192 local url="${REPORT_UPLOAD_PROD_URL}" |
| 155 if is_official; then | 193 local chromeos_version="$(get_key_value "${meta_path}" "ver")" |
| 156 url="${REPORT_UPLOAD_PROD_URL}" | 194 local board="$(get_board)" |
| 157 fi | 195 local hwclass="$(get_hardware_class)" |
| 196 local payload_extension="${kind}" |
| 197 [ "${kind}" = "minidump" ] && payload_extension="dmp" |
| 198 local report_payload="$(get_base "${meta_path}").${payload_extension}" |
| 158 lecho "Sending crash:" | 199 lecho "Sending crash:" |
| 159 lecho " Scheduled to send in ${sleep_time}s" | 200 lecho " Scheduled to send in ${sleep_time}s" |
| 160 lecho " Report: ${report_path} (${kind})" | 201 lecho " Metadata: ${meta_path} (${kind})" |
| 161 lecho " URL: ${url}" | 202 lecho " Payload: ${report_payload}" |
| 162 lecho " Product: ${CHROMEOS_PRODUCT}" | |
| 163 lecho " Version: ${chromeos_version}" | 203 lecho " Version: ${chromeos_version}" |
| 204 if is_mock; then |
| 205 lecho " Product: ${CHROMEOS_PRODUCT}" |
| 206 lecho " URL: ${url}" |
| 207 lecho " Board: ${board}" |
| 208 lecho " HWClass: ${hwclass}" |
| 209 fi |
| 164 lecho " Exec name: ${exec_name}" | 210 lecho " Exec name: ${exec_name}" |
| 165 if [ -f "${MOCK_CRASH_SENDING}" ]; then | 211 if is_mock; then |
| 166 local mock_in=$(cat "${MOCK_CRASH_SENDING}") | 212 local mock_in=$(cat "${MOCK_CRASH_SENDING}") |
| 167 if [ "${mock_in}" = "" ]; then | 213 if [ "${mock_in}" = "" ]; then |
| 168 lecho "Mocking successful send" | 214 lecho "Mocking successful send" |
| 169 return 0 | 215 return 0 |
| 170 else | 216 else |
| 171 lecho "Mocking unsuccessful send" | 217 lecho "Mocking unsuccessful send" |
| 172 return 1 | 218 return 1 |
| 173 fi | 219 fi |
| 174 fi | 220 fi |
| 175 | 221 |
| 176 if ! sleep ${sleep_time}; then | 222 if ! sleep ${sleep_time}; then |
| 177 lecho "Sleep failed" | 223 lecho "Sleep failed" |
| 178 return 1 | 224 return 1 |
| 179 fi | 225 fi |
| 180 | 226 |
| 181 local report_id="${TMP_DIR}/report_id" | 227 local report_id="${TMP_DIR}/report_id" |
| 182 local curl_stderr="${TMP_DIR}/curl_stderr" | 228 local curl_stderr="${TMP_DIR}/curl_stderr" |
| 183 | 229 |
| 184 set +e | 230 set +e |
| 185 curl "${url}" \ | 231 curl "${url}" \ |
| 186 -F "prod=${CHROMEOS_PRODUCT}" \ | 232 -F "prod=${CHROMEOS_PRODUCT}" \ |
| 187 -F "ver=${chromeos_version}" \ | 233 -F "ver=${chromeos_version}" \ |
| 188 -F "upload_file_${kind}=@${report_path}" \ | 234 -F "upload_file_${kind}=@${report_payload}" \ |
| 235 -F "board=${board}" \ |
| 236 -F "hwclass=${hwclass}" \ |
| 189 -F "exec_name=${exec_name}" \ | 237 -F "exec_name=${exec_name}" \ |
| 190 -F "guid=<${CONSENT_ID}" -o "${report_id}" 2>"${curl_stderr}" | 238 -F "guid=<${CONSENT_ID}" -o "${report_id}" 2>"${curl_stderr}" |
| 191 curl_result=$? | 239 curl_result=$? |
| 192 set -e | 240 set -e |
| 193 | 241 |
| 194 if [ ${curl_result} -eq 0 ]; then | 242 if [ ${curl_result} -eq 0 ]; then |
| 195 lecho "Crash report receipt ID $(cat ${report_id})" | 243 lecho "Crash report receipt ID $(cat ${report_id})" |
| 196 else | 244 else |
| 197 lecho "Crash sending failed with: $(cat ${curl_stderr})" | 245 lecho "Crash sending failed with: $(cat ${curl_stderr})" |
| 198 fi | 246 fi |
| 199 | 247 |
| 200 rm -f "${report_id}" | 248 rm -f "${report_id}" |
| 201 | 249 |
| 202 return ${curl_result} | 250 return ${curl_result} |
| 203 } | 251 } |
| 204 | 252 |
| 253 # *.meta files always end with done=1 so we can tell if they are complete. |
| 254 is_complete_metadata() { |
| 255 grep -q "done=1" "$1" |
| 256 } |
| 257 |
| 258 # Remove the given report path. |
| 259 remove_report() { |
| 260 local base="${1%.*}" |
| 261 rm -f -- "${base}".* |
| 262 } |
| 263 |
| 205 # Send all crashes from the given directory. | 264 # Send all crashes from the given directory. |
| 206 send_crashes() { | 265 send_crashes() { |
| 207 local dir="$1" | 266 local dir="$1" |
| 208 lecho "Considering crashes in ${dir}" | |
| 209 | 267 |
| 210 # Cycle through minidumps, most recent first. That way if we're about | 268 # Cycle through minidumps, most recent first. That way if we're about |
| 211 # to exceed the daily rate, we send the most recent minidumps. | 269 # to exceed the daily rate, we send the most recent minidumps. |
| 212 if [ ! -d "${dir}" ]; then | 270 if [ ! -d "${dir}" ]; then |
| 213 return | 271 return |
| 214 fi | 272 fi |
| 215 for file in $(ls -1t "${dir}"); do | |
| 216 local report_path="${dir}/${file}" | |
| 217 lecho "Considering file ${report_path}" | |
| 218 local kind=$(get_kind "${report_path}") | |
| 219 | 273 |
| 220 if [ "${kind}" = "core" ]; then | 274 # Consider any old files which still have no corresponding meta file |
| 221 lecho "Ignoring core file." | 275 # as orphaned, and remove them. |
| 222 continue | 276 for old_file in $(${FIND} "${dir}" -mindepth 1 \ |
| 223 elif [ "${kind}" != "minidump" ] && [ "${kind}" != "kcrash" ]; then | 277 -mmin +$((24 * 60)) -type f); do |
| 224 lecho "Unknown report kind: ${kind}. Removing report." | 278 if [ ! -e "$(get_base "${old_file}").meta" ]; then |
| 225 rm -f "${report_path}" | 279 lecho "Removing old orphaned file: ${old_file}." |
| 280 rm -f -- "${old_file}" |
| 281 fi |
| 282 done |
| 283 |
| 284 # Look through all metadata (*.meta) files, if any exist. |
| 285 for meta_path in $(ls -1t "${dir}"/*.meta 2>/dev/null); do |
| 286 lecho "Considering metadata ${meta_path}." |
| 287 local kind=$(get_kind "${meta_path}") |
| 288 |
| 289 if [ "${kind}" != "minidump" ] && [ "${kind}" != "kcrash" ]; then |
| 290 lecho "Unknown report kind. Removing report." |
| 291 remove_report "${meta_path}" |
| 226 continue | 292 continue |
| 227 fi | 293 fi |
| 228 if ! check_rate; then | 294 |
| 229 lecho "Sending ${report_path} would exceed rate. Leaving for later." | 295 if is_feedback_disabled; then |
| 296 lecho "Uploading is disabled. Removing crash." |
| 297 remove_report "${meta_path}" |
| 298 continue |
| 299 fi |
| 300 |
| 301 if ! is_mock && ! is_official; then |
| 302 lecho "Not an official OS version. Removing crash." |
| 303 remove_report "${meta_path}" |
| 304 continue |
| 305 fi |
| 306 |
| 307 if is_on_3g; then |
| 308 lecho "Not sending crash reports while on 3G, saving for later." |
| 230 return 0 | 309 return 0 |
| 231 fi | 310 fi |
| 232 local chromeos_version=$(get_version) | 311 |
| 233 if is_feedback_disabled; then | 312 if ! is_complete_metadata "${meta_path}"; then |
| 234 lecho "Uploading is disabled. Removing crash." | 313 # This report is incomplete, so if it's old, just remove it. |
| 235 rm "${report_path}" | 314 local old_meta=$(${FIND} "${dir}" -mindepth 1 -name \ |
| 236 elif is_on_3g; then | 315 $(basename "${meta_path}") -mmin +$((24 * 60)) -type f) |
| 237 lecho "Not sending crash report while on 3G, saving for later." | 316 if [ -n "${old_meta}" ]; then |
| 238 elif send_crash "${report_path}"; then | 317 lecho "Removing old incomplete metadata." |
| 239 # Send was successful, now remove | 318 remove_report "${meta_path}" |
| 240 lecho "Successfully sent crash ${report_path} and removing" | 319 else |
| 241 rm "${report_path}" | 320 lecho "Ignoring recent incomplete metadata." |
| 242 else | 321 fi |
| 243 lecho "Problem sending ${report_path}, not removing" | 322 continue |
| 244 fi | 323 fi |
| 324 |
| 325 if ! check_rate; then |
| 326 lecho "Sending ${meta_path} would exceed rate. Leaving for later." |
| 327 return 0 |
| 328 fi |
| 329 |
| 330 if ! send_crash "${meta_path}"; then |
| 331 lecho "Problem sending ${meta_path}, not removing." |
| 332 continue |
| 333 fi |
| 334 |
| 335 # Send was successful, now remove. |
| 336 lecho "Successfully sent crash ${meta_path} and removing." |
| 337 remove_report "${meta_path}" |
| 245 done | 338 done |
| 246 } | 339 } |
| 247 | 340 |
| 248 main() { | 341 main() { |
| 249 trap cleanup EXIT INT TERM | 342 trap cleanup EXIT INT TERM |
| 250 if [ -e "${PAUSE_CRASH_SENDING}" ]; then | 343 if [ -e "${PAUSE_CRASH_SENDING}" ]; then |
| 251 lecho "Exiting early due to ${PAUSE_CRASH_SENDING}" | 344 lecho "Exiting early due to ${PAUSE_CRASH_SENDING}." |
| 252 exit 1 | 345 exit 1 |
| 253 fi | 346 fi |
| 254 | 347 |
| 255 check_not_already_running | 348 check_not_already_running |
| 256 | 349 |
| 257 if [ ! -x "${FIND}" ]; then | 350 if [ ! -x "${FIND}" ]; then |
| 258 lecho "Fatal: Crash sending disabled: ${FIND} not found." | 351 lecho "Fatal: Crash sending disabled: ${FIND} not found." |
| 259 exit 1 | 352 exit 1 |
| 260 fi | 353 fi |
| 261 | 354 |
| 262 TMP_DIR="$(mktemp -d /tmp/crash_sender.XXXX)" | 355 TMP_DIR="$(mktemp -d /tmp/crash_sender.XXXX)" |
| 263 | 356 |
| 264 # Send system-wide crashes | 357 # Send system-wide crashes |
| 265 send_crashes "/var/spool/crash" | 358 send_crashes "/var/spool/crash" |
| 266 | 359 |
| 267 # Send user-specific crashes | 360 # Send user-specific crashes |
| 268 send_crashes "/home/chronos/user/crash" | 361 send_crashes "/home/chronos/user/crash" |
| 269 } | 362 } |
| 270 | 363 |
| 271 main | 364 main |
| OLD | NEW |