OLD | NEW |
| (Empty) |
1 #!/bin/sh | |
2 | |
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 | |
5 # found in the LICENSE file. | |
6 | |
7 set -e | |
8 | |
9 # Product ID in crash report | |
10 CHROMEOS_PRODUCT=ChromeOS | |
11 | |
12 # Send up to 8 crashes per day. | |
13 MAX_CRASH_RATE=8 | |
14 | |
15 # Minidump uploading tool (provided by Google Breakpad). | |
16 MINIDUMP_UPLOADER=/usr/bin/minidump_upload | |
17 | |
18 # URL to send non-official build crashes to. | |
19 MINIDUMP_UPLOAD_STAGING_URL="http://clients2.google.com/cr/staging_report" | |
20 | |
21 # URL to send official build crashes to. | |
22 MINIDUMP_UPLOAD_PROD_URL="http://clients2.google.com/cr/report" | |
23 | |
24 # File whose existence mocks crash sending. If empty we pretend the | |
25 # crash sending was successful, otherwise unsuccessful. | |
26 MOCK_CRASH_SENDING="/tmp/mock-crash-sending" | |
27 | |
28 # File whose existence causes crash sending to be delayed (for testing). | |
29 PAUSE_CRASH_SENDING="/tmp/pause-crash-sending" | |
30 | |
31 # File whose existence implies we're running and not to start again. | |
32 RUN_FILE="/var/run/crash_sender.pid" | |
33 | |
34 # Maximum time to sleep between sends. | |
35 SECONDS_SEND_SPREAD=600 | |
36 | |
37 # The syslog tag for all logging we emit. | |
38 TAG="$(basename $0)[$$]" | |
39 | |
40 # Directory to store timestamp files indicating the uploads in the past 24 | |
41 # hours. | |
42 TIMESTAMPS_DIR="/var/lib/crash_sender" | |
43 | |
44 lecho() { | |
45 logger -t "${TAG}" "$@" | |
46 } | |
47 | |
48 remove_run_file() { | |
49 rm -f "${RUN_FILE}" | |
50 } | |
51 | |
52 check_not_already_running() { | |
53 if [ ! -f "${RUN_FILE}" ]; then | |
54 return | |
55 fi | |
56 local last_pid=$(cat "${RUN_FILE}") | |
57 if [ ! -f "/proc/${last_pid}/cmdline" ]; then | |
58 trap remove_run_file EXIT | |
59 echo $$ > "${RUN_FILE}" | |
60 return | |
61 fi | |
62 # This could just be an unrelated process, but it's ok to be conservative. | |
63 lecho "Already running. Exiting now." | |
64 exit 1 | |
65 } | |
66 | |
67 get_version() { | |
68 grep ^CHROMEOS_RELEASE_VERSION /etc/lsb-release | cut -d = -f 2- | |
69 } | |
70 | |
71 is_official() { | |
72 grep ^CHROMEOS_RELEASE_DESCRIPTION /etc/lsb-release | cut -d = -f 2- | \ | |
73 grep Official | |
74 } | |
75 | |
76 # Generate a uniform random number in 0..max-1. | |
77 generate_uniform_random() { | |
78 local max=$1 | |
79 local random="$(od -An -N4 -tu /dev/urandom)" | |
80 echo $((random % max)) | |
81 } | |
82 | |
83 is_feedback_disabled() { | |
84 # See crosbug.com/3303. | |
85 return 1 | |
86 } | |
87 | |
88 is_on_3g() { | |
89 # See crosbug.com/3304. | |
90 return 1 | |
91 } | |
92 | |
93 # Check if sending a crash now does not exceed the maximum 24hr rate and | |
94 # commit to doing so, if not. | |
95 check_rate() { | |
96 mkdir -p ${TIMESTAMPS_DIR} | |
97 # Only consider minidumps written in the past 24 hours by removing all older. | |
98 find "${TIMESTAMPS_DIR}" -mindepth 1 -mmin +$((24 * 60)) -exec rm '{}' ';' | |
99 local sends_in_24hrs=$(echo "${TIMESTAMPS_DIR}"/* | wc -w) | |
100 lecho "Current send rate: ${sends_in_24hrs}sends/24hrs" | |
101 if [ ${sends_in_24hrs} -ge ${MAX_CRASH_RATE} ]; then | |
102 lecho "Cannot send more crashes:" | |
103 lecho " current ${sends_in_24hrs}send/24hrs >= " \ | |
104 "max ${MAX_CRASH_RATE}send/24hrs" | |
105 return 1 | |
106 fi | |
107 mktemp "${TIMESTAMPS_DIR}"/XXXX > /dev/null | |
108 return 0 | |
109 } | |
110 | |
111 send_crash() { | |
112 local sleep_time=$(generate_uniform_random $SECONDS_SEND_SPREAD) | |
113 local url="${MINIDUMP_UPLOAD_STAGING_URL}" | |
114 if is_official; then | |
115 url="${MINIDUMP_UPLOAD_PROD_URL}" | |
116 fi | |
117 lecho "Sending crash:" | |
118 lecho " Scheduled to send in ${sleep_time}s" | |
119 lecho " Minidump: ${minidump_path}" | |
120 lecho " URL: ${url}" | |
121 lecho " Product: ${CHROMEOS_PRODUCT}" | |
122 lecho " Version: ${chromeos_version}" | |
123 if [ -s "${minidump_path}" ]; then | |
124 # We cannot tell much from the minidump without symbols, but we can tell | |
125 # at least what modules were loaded at the time of crash | |
126 local modules="$(/usr/bin/minidump_dump "${minidump_path}" 2>&- | \ | |
127 grep 'code_file' | sed -e 's/^.* = "//g;s/"//g' | \ | |
128 tr '\n' ' ')" | |
129 lecho " Mapped: ${modules}" | |
130 fi | |
131 if [ -f "${MOCK_CRASH_SENDING}" ]; then | |
132 local mock_in=$(cat "${MOCK_CRASH_SENDING}") | |
133 if [ "${mock_in}" = "" ]; then | |
134 lecho "Mocking successful send" | |
135 return 0 | |
136 else | |
137 lecho "Mocking unsuccessful send" | |
138 return 1 | |
139 fi | |
140 fi | |
141 | |
142 if ! sleep ${sleep_time}; then | |
143 lecho "Sleep failed" | |
144 return 1 | |
145 fi | |
146 | |
147 "${MINIDUMP_UPLOADER}" -p "${CHROMEOS_PRODUCT}" \ | |
148 -v "${chromeos_version}" "${minidump_path}" "${url}" | |
149 return $? | |
150 } | |
151 | |
152 # Send all crashes from the given directory. The directory is currently | |
153 # expected to just contain a bunch of minidumps - but this will change | |
154 # over time to be a directory of directories where the minidump and core | |
155 # file are in the directory as well as other metadata about the context | |
156 # of the crash (executable name for instance). | |
157 send_crashes() { | |
158 local dir="$1" | |
159 lecho "Considering crashes in ${dir}" | |
160 # Cycle through minidumps, most recent first. That way if we're about | |
161 # to exceed the daily rate, we send the most recent minidumps. | |
162 if [ ! -d "${dir}" ]; then | |
163 return | |
164 fi | |
165 for file in $(ls -1t "${dir}"); do | |
166 local minidump_path="${dir}/${file}" | |
167 lecho "Considering crash ${minidump_path}" | |
168 if ! check_rate; then | |
169 lecho "Sending ${minidump_path} would exceed rate. Leaving for later." | |
170 return 0 | |
171 fi | |
172 local chromeos_version=$(get_version) | |
173 if is_feedback_disabled; then | |
174 lecho "Uploading is disabled. Removing crash." | |
175 rm "${minidump_path}" | |
176 elif is_on_3g; then | |
177 lecho "Not sending crash report while on 3G, saving for later." | |
178 elif send_crash ${minidump_path}; then | |
179 # Send was successful, now remove | |
180 lecho "Successfully sent crash ${minidump_path} and removing" | |
181 rm "${minidump_path}" | |
182 else | |
183 lecho "Problem sending ${minidump_path}, not removing" | |
184 fi | |
185 done | |
186 } | |
187 | |
188 main() { | |
189 lecho "Starting" | |
190 if [ -e "${PAUSE_CRASH_SENDING}" ]; then | |
191 lecho "Exiting early due to ${PAUSE_CRASH_SENDING}" | |
192 exit 1 | |
193 fi | |
194 | |
195 check_not_already_running | |
196 | |
197 # Send system-wide crashes | |
198 send_crashes "/var/spool/crash" | |
199 | |
200 # Send user-specific crashes | |
201 send_crashes "/home/chronos/user/crash" | |
202 | |
203 lecho "Done" | |
204 } | |
205 | |
206 main | |
OLD | NEW |