Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: ios/chrome/browser/crash_report/breakpad_helper.mm

Issue 1207353005: [iOS] Upstream some stability code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
6
7 #import <Foundation/Foundation.h>
8
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/debug/crash_logging.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/path_service.h"
18 #include "base/strings/sys_string_conversions.h"
19 #include "ios/chrome/browser/chrome_paths.h"
20 #import "ios/chrome/browser/crash_report/crash_report_user_application_state.h"
21 #include "ios/web/public/web_thread.h"
22
23 // TODO(stuartmorgan): Move this up where it belongs once
24 // http://code.google.com/p/google-breakpad/issues/detail?id=487
25 // is fixed. For now, put it at the end to avoid compiler errors.
26 #import "breakpad/src/client/ios/BreakpadController.h"
27
28 namespace breakpad_helper {
29
30 namespace {
31
32 // Key in NSUserDefaults for a Boolean value that stores whether to upload
33 // crash reports.
34 NSString* const kCrashReportsUploadingEnabledKey =
35 @"CrashReportsUploadingEnabled";
36
37 NSString* const kCrashedInBackground = @"crashed_in_background";
38 NSString* const kFreeDiskInKB = @"free_disk_in_kb";
39 NSString* const kFreeMemoryInKB = @"free_memory_in_kb";
40 NSString* const kMemoryWarningInProgress = @"memory_warning_in_progress";
41 NSString* const kMemoryWarningCount = @"memory_warning_count";
42 NSString* const kUptimeAtRestoreInMs = @"uptime_at_restore_in_ms";
43 NSString* const kUploadedInRecoveryMode = @"uploaded_in_recovery_mode";
44
45 // Multiple state information are combined into one CrachReportMultiParameter
46 // to save limited and finite number of ReportParameters.
47 // These are the values grouped in the user_application_state parameter.
48 NSString* const kDataProxyIsEnabled = @"dataproxy";
49 NSString* const kOrientationState = @"orient";
50 NSString* const kSignedIn = @"signIn";
51 NSString* const kIsShowingPDF = @"pdf";
52 NSString* const kVideoPlaying = @"avplay";
53
54 // Whether the crash reporter is enabled.
55 bool g_crash_reporter_enabled = false;
56
57 void DeleteAllReportsInDirectory(base::FilePath directory) {
58 base::FileEnumerator enumerator(directory, false,
59 base::FileEnumerator::FILES);
60 base::FilePath cur_file;
61 while (!(cur_file = enumerator.Next()).value().empty()) {
62 if (cur_file.BaseName().value() != kReporterLogFilename)
63 base::DeleteFile(cur_file, false);
64 }
65 }
66
67 // Callback for base::debug::SetCrashKeyReportingFunctions
68 void SetCrashKeyValueImpl(const base::StringPiece& key,
69 const base::StringPiece& value) {
70 AddReportParameter(base::SysUTF8ToNSString(key.as_string()),
71 base::SysUTF8ToNSString(value.as_string()), true);
72 }
73
74 // Callback for base::debug::SetCrashKeyReportingFunctions
75 void ClearCrashKeyValueImpl(const base::StringPiece& key) {
76 RemoveReportParameter(base::SysUTF8ToNSString(key.as_string()));
77 }
78
79 // Callback for logging::SetLogMessageHandler
80 bool FatalMessageHandler(int severity,
81 const char* file,
82 int line,
83 size_t message_start,
84 const std::string& str) {
85 // Do not handle non-FATAL.
86 if (severity != logging::LOG_FATAL)
87 return false;
88
89 // In case of OOM condition, this code could be reentered when
90 // constructing and storing the key. Using a static is not
91 // thread-safe, but if multiple threads are in the process of a
92 // fatal crash at the same time, this should work.
93 static bool guarded = false;
94 if (guarded)
95 return false;
96
97 base::AutoReset<bool> guard(&guarded, true);
98
99 // Only log last path component. This matches logging.cc.
100 if (file) {
101 const char* slash = strrchr(file, '/');
102 if (slash)
103 file = slash + 1;
104 }
105
106 NSString* fatal_key = @"LOG_FATAL";
107 NSString* fatal_value = [NSString
108 stringWithFormat:@"%s:%d: %s", file, line, str.c_str() + message_start];
109 AddReportParameter(fatal_key, fatal_value, true);
110
111 // Rather than including the code to force the crash here, allow the
112 // caller to do it.
113 return false;
114 }
115
116 // Caches the uploading flag in NSUserDefaults, so that we can access the value
117 // in safe mode.
118 void CacheUploadingEnabled(bool uploading_enabled) {
119 NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults];
120 [user_defaults setBool:uploading_enabled ? YES : NO
121 forKey:kCrashReportsUploadingEnabledKey];
122 }
123
124 } // namespace
125
126 void Start(const std::string& channel_name) {
127 DCHECK(!g_crash_reporter_enabled);
128 [[BreakpadController sharedInstance] start:YES];
129 base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValueImpl,
130 &ClearCrashKeyValueImpl);
131 logging::SetLogMessageHandler(&FatalMessageHandler);
132 g_crash_reporter_enabled = true;
133 // Register channel information.
134 if (channel_name.length()) {
135 AddReportParameter(@"channel", base::SysUTF8ToNSString(channel_name), true);
136 }
137 // Notifying the PathService on the location of the crashes so that crashes
138 // can be displayed to the user on the about:crashes page.
139 NSArray* cachesDirectories = NSSearchPathForDirectoriesInDomains(
140 NSCachesDirectory, NSUserDomainMask, YES);
141 NSString* cachePath = [cachesDirectories objectAtIndex:0];
142 NSString* dumpDirectory =
143 [cachePath stringByAppendingPathComponent:@kDefaultLibrarySubdirectory];
144 PathService::Override(ios::DIR_CRASH_DUMPS,
145 base::FilePath(base::SysNSStringToUTF8(dumpDirectory)));
146 }
147
148 void SetEnabled(bool enabled) {
149 if (g_crash_reporter_enabled == enabled)
150 return;
151 g_crash_reporter_enabled = enabled;
152 if (g_crash_reporter_enabled) {
153 [[BreakpadController sharedInstance] start:NO];
154 } else {
155 [[BreakpadController sharedInstance] stop];
156 CacheUploadingEnabled(false);
157 }
158 }
159
160 void SetUploadingEnabled(bool enabled) {
161 CacheUploadingEnabled(g_crash_reporter_enabled && enabled);
162
163 if (!g_crash_reporter_enabled)
164 return;
165 [[BreakpadController sharedInstance] setUploadingEnabled:enabled];
166 }
167
168 bool IsUploadingEnabled() {
169 // Return the value cached by CacheUploadingEnabled().
170 return [[NSUserDefaults standardUserDefaults]
171 boolForKey:kCrashReportsUploadingEnabledKey];
172 }
173
174 void CleanupCrashReports() {
175 base::FilePath crash_directory;
176 PathService::Get(ios::DIR_CRASH_DUMPS, &crash_directory);
177 web::WebThread::PostBlockingPoolTask(
178 FROM_HERE, base::Bind(&DeleteAllReportsInDirectory, crash_directory));
179 }
180
181 void AddReportParameter(NSString* key, NSString* value, bool async) {
182 if (!g_crash_reporter_enabled)
183 return;
184 if (async) {
185 [[BreakpadController sharedInstance] addUploadParameter:value forKey:key];
186 return;
187 }
188 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
189 [[BreakpadController sharedInstance] withBreakpadRef:^(BreakpadRef ref) {
190 if (ref)
191 BreakpadAddUploadParameter(ref, key, value);
192 dispatch_semaphore_signal(semaphore);
193 }];
194 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
195 dispatch_release(semaphore);
196 }
197
198 int GetCrashReportCount() {
199 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
200 __block int outerCrashReportCount = 0;
201 [[BreakpadController sharedInstance] getCrashReportCount:^(int count) {
202 outerCrashReportCount = count;
203 dispatch_semaphore_signal(semaphore);
204 }];
205 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
206 dispatch_release(semaphore);
207 return outerCrashReportCount;
208 }
209
210 void GetCrashReportCount(void (^callback)(int)) {
211 [[BreakpadController sharedInstance] getCrashReportCount:callback];
212 }
213
214 bool HasReportToUpload() {
215 return GetCrashReportCount() > 0;
216 }
217
218 void RemoveReportParameter(NSString* key) {
219 if (!g_crash_reporter_enabled)
220 return;
221 [[BreakpadController sharedInstance] removeUploadParameterForKey:key];
222 }
223
224 void SetCurrentlyInBackground(bool background) {
225 if (background)
226 AddReportParameter(kCrashedInBackground, @"yes", true);
227 else
228 RemoveReportParameter(kCrashedInBackground);
229 }
230
231 void SetMemoryWarningCount(int count) {
232 if (count) {
233 AddReportParameter(kMemoryWarningCount,
234 [NSString stringWithFormat:@"%d", count], true);
235 } else {
236 RemoveReportParameter(kMemoryWarningCount);
237 }
238 }
239
240 void SetMemoryWarningInProgress(bool value) {
241 if (value)
242 AddReportParameter(kMemoryWarningInProgress, @"yes", true);
243 else
244 RemoveReportParameter(kMemoryWarningInProgress);
245 }
246
247 void SetCurrentFreeMemoryInKB(int value) {
248 AddReportParameter(kFreeMemoryInKB, [NSString stringWithFormat:@"%d", value],
249 true);
250 }
251
252 void SetCurrentFreeDiskInKB(int value) {
253 AddReportParameter(kFreeDiskInKB, [NSString stringWithFormat:@"%d", value],
254 true);
255 }
256
257 void SetCurrentTabIsPDF(bool value) {
258 if (value) {
259 [[CrashReportUserApplicationState sharedInstance]
260 incrementValue:kIsShowingPDF];
261 } else {
262 [[CrashReportUserApplicationState sharedInstance]
263 decrementValue:kIsShowingPDF];
264 }
265 }
266
267 void SetCurrentOrientation(int statusBarOrientation, int deviceOrientation) {
268 DCHECK((statusBarOrientation < 10) && (deviceOrientation < 10));
269 int deviceAndUIOrientation = 10 * statusBarOrientation + deviceOrientation;
270 [[CrashReportUserApplicationState sharedInstance]
271 setValue:kOrientationState
272 withValue:deviceAndUIOrientation];
273 }
274
275 void SetCurrentlySignedIn(bool signedIn) {
276 if (signedIn) {
277 [[CrashReportUserApplicationState sharedInstance] setValue:kSignedIn
278 withValue:1];
279 } else {
280 [[CrashReportUserApplicationState sharedInstance] removeValue:kSignedIn];
281 }
282 }
283
284 void SetDataReductionProxyIsEnabled(bool value) {
285 if (value) {
286 [[CrashReportUserApplicationState sharedInstance]
287 setValue:kDataProxyIsEnabled
288 withValue:value];
289 } else {
290 [[CrashReportUserApplicationState sharedInstance]
291 removeValue:kDataProxyIsEnabled];
292 }
293 }
294
295 void MediaStreamPlaybackDidStart() {
296 [[CrashReportUserApplicationState sharedInstance]
297 incrementValue:kVideoPlaying];
298 }
299
300 void MediaStreamPlaybackDidStop() {
301 [[CrashReportUserApplicationState sharedInstance]
302 decrementValue:kVideoPlaying];
303 }
304
305 // Records the current process uptime in the "uptime_at_restore_in_ms". This
306 // will allow engineers to dremel crash logs to find crash whose delta between
307 // process uptime at crash and process uptime at restore is smaller than X
308 // seconds and find insta-crashers.
309 void WillStartCrashRestoration() {
310 if (!g_crash_reporter_enabled)
311 return;
312 // We use gettimeofday and BREAKPAD_PROCESS_START_TIME to compute the
313 // uptime to stay as close as possible as how breakpad computes the
314 // "ProcessUptime" in order to have meaningful comparison in dremel.
315 struct timeval tv;
316 gettimeofday(&tv, NULL);
317 // The values stored in the breakpad log are only accessible through a
318 // BreakpadRef. To record the process uptime at restore, the value of
319 // BREAKPAD_PROCESS_START_TIME is required to compute the delta.
320 [[BreakpadController sharedInstance] withBreakpadRef:^(BreakpadRef ref) {
321 if (!ref)
322 return;
323 NSString* processStartTimeSecondsString =
324 BreakpadKeyValue(ref, @BREAKPAD_PROCESS_START_TIME);
325 if (!processStartTimeSecondsString)
326 return;
327
328 time_t processStartTimeSeconds =
329 [processStartTimeSecondsString longLongValue];
330 time_t processUptimeSeconds = tv.tv_sec - processStartTimeSeconds;
331 unsigned long long processUptimeMilliseconds =
332 static_cast<unsigned long long>(processUptimeSeconds) *
333 base::Time::kMillisecondsPerSecond;
334 BreakpadAddUploadParameter(
335 ref, kUptimeAtRestoreInMs,
336 [NSString stringWithFormat:@"%llu", processUptimeMilliseconds]);
337 }];
338 }
339
340 void StartUploadingReportsInRecoveryMode() {
341 if (!g_crash_reporter_enabled)
342 return;
343 [[BreakpadController sharedInstance] stop];
344 [[BreakpadController sharedInstance] setParametersToAddAtUploadTime:@{
345 kUploadedInRecoveryMode : @"yes"
346 }];
347 [[BreakpadController sharedInstance] setUploadInterval:1];
348 [[BreakpadController sharedInstance] start:NO];
349 [[BreakpadController sharedInstance] setUploadingEnabled:YES];
350 }
351
352 void RestoreDefaultConfiguration() {
353 if (!g_crash_reporter_enabled)
354 return;
355 [[BreakpadController sharedInstance] stop];
356 [[BreakpadController sharedInstance] resetConfiguration];
357 [[BreakpadController sharedInstance] start:NO];
358 [[BreakpadController sharedInstance] setUploadingEnabled:NO];
359 }
360
361 } // namespace breakpad_helper
OLDNEW
« no previous file with comments | « ios/chrome/browser/crash_report/breakpad_helper.h ('k') | ios/chrome/browser/crash_report/crash_report_multi_parameter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698