OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/chrome_application_mac.h" | 5 #import "chrome/browser/chrome_browser_application_mac.h" |
6 | 6 |
7 #import "base/histogram.h" | 7 #import "base/histogram.h" |
8 #import "base/logging.h" | 8 #import "base/logging.h" |
9 #import "base/scoped_nsobject.h" | 9 #import "base/scoped_nsobject.h" |
10 #import "base/sys_string_conversions.h" | 10 #import "base/sys_string_conversions.h" |
11 #import "chrome/app/breakpad_mac.h" | 11 #import "chrome/app/breakpad_mac.h" |
12 #import "chrome/browser/cocoa/chrome_event_processing_window.h" | 12 #import "chrome/browser/cocoa/chrome_event_processing_window.h" |
13 #import "chrome/browser/cocoa/objc_method_swizzle.h" | 13 #import "chrome/browser/cocoa/objc_method_swizzle.h" |
14 #import "chrome/browser/renderer_host/render_widget_host_view_mac.h" | |
15 | 14 |
16 // The implementation of NSExceptions break various assumptions in the | 15 // The implementation of NSExceptions break various assumptions in the |
17 // Chrome code. This category defines a replacement for | 16 // Chrome code. This category defines a replacement for |
18 // -initWithName:reason:userInfo: for purposes of forcing a break in | 17 // -initWithName:reason:userInfo: for purposes of forcing a break in |
19 // the debugger when an exception is raised. -raise sounds more | 18 // the debugger when an exception is raised. -raise sounds more |
20 // obvious to intercept, but it doesn't catch the original throw | 19 // obvious to intercept, but it doesn't catch the original throw |
21 // because the objc runtime doesn't use it. | 20 // because the objc runtime doesn't use it. |
22 @interface NSException (NSExceptionSwizzle) | 21 @interface NSException (NSExceptionSwizzle) |
23 - (id)chromeInitWithName:(NSString *)aName | 22 - (id)chromeInitWithName:(NSString *)aName |
24 reason:(NSString *)aReason | 23 reason:(NSString *)aReason |
(...skipping 17 matching lines...) Expand all Loading... |
42 DLOG(ERROR) << "Someone is preparing to raise an exception! " | 41 DLOG(ERROR) << "Someone is preparing to raise an exception! " |
43 << base::SysNSStringToUTF8(aName) << " *** " | 42 << base::SysNSStringToUTF8(aName) << " *** " |
44 << base::SysNSStringToUTF8(aReason); | 43 << base::SysNSStringToUTF8(aReason); |
45 NOTREACHED(); | 44 NOTREACHED(); |
46 | 45 |
47 // Forward to the original version. | 46 // Forward to the original version. |
48 return gOriginalInitIMP(self, _cmd, aName, aReason, someUserInfo); | 47 return gOriginalInitIMP(self, _cmd, aName, aReason, someUserInfo); |
49 } | 48 } |
50 @end | 49 @end |
51 | 50 |
52 namespace CrApplicationNSException { | 51 namespace chrome_browser_application_mac { |
53 | 52 |
54 // Maximum number of known named exceptions we'll support. There is | 53 // Maximum number of known named exceptions we'll support. There is |
55 // no central registration, but I only find about 75 possibilities in | 54 // no central registration, but I only find about 75 possibilities in |
56 // the system frameworks, and many of them are probably not | 55 // the system frameworks, and many of them are probably not |
57 // interesting to track in aggregate (those relating to distributed | 56 // interesting to track in aggregate (those relating to distributed |
58 // objects, for instance). | 57 // objects, for instance). |
59 const size_t kKnownNSExceptionCount = 25; | 58 const size_t kKnownNSExceptionCount = 25; |
60 | 59 |
61 const size_t kUnknownNSException = kKnownNSExceptionCount; | 60 const size_t kUnknownNSException = kKnownNSExceptionCount; |
62 | 61 |
(...skipping 29 matching lines...) Expand all Loading... |
92 return kUnknownNSException; | 91 return kUnknownNSException; |
93 } | 92 } |
94 | 93 |
95 void RecordExceptionWithUma(NSException* exception) { | 94 void RecordExceptionWithUma(NSException* exception) { |
96 static LinearHistogram histogram("OSX.NSException", 0, kUnknownNSException, | 95 static LinearHistogram histogram("OSX.NSException", 0, kUnknownNSException, |
97 kUnknownNSException + 1); | 96 kUnknownNSException + 1); |
98 histogram.SetFlags(kUmaTargetedHistogramFlag); | 97 histogram.SetFlags(kUmaTargetedHistogramFlag); |
99 histogram.Add(BinForException(exception)); | 98 histogram.Add(BinForException(exception)); |
100 } | 99 } |
101 | 100 |
102 } // CrApplicationNSException | 101 void Terminate() { |
| 102 [NSApp terminate:nil]; |
| 103 } |
| 104 |
| 105 } // namespace chrome_browser_application_mac |
103 | 106 |
104 namespace { | 107 namespace { |
105 | 108 |
106 // Helper to make it easy to get crash keys right. | 109 // Helper to make it easy to get crash keys right. |
107 // TODO(shess): Find a better home for this. app/breakpad_mac.h | 110 // TODO(shess): Find a better home for this. app/breakpad_mac.h |
108 // doesn't work. | 111 // doesn't work. |
109 class ScopedCrashKey { | 112 class ScopedCrashKey { |
110 public: | 113 public: |
111 ScopedCrashKey(NSString* key, NSString* value) | 114 ScopedCrashKey(NSString* key, NSString* value) |
112 : crash_key_([key retain]) { | 115 : crash_key_([key retain]) { |
(...skipping 13 matching lines...) Expand all Loading... |
126 BOOL SwizzleNSExceptionInit() { | 129 BOOL SwizzleNSExceptionInit() { |
127 gOriginalInitIMP = ObjcEvilDoers::SwizzleImplementedInstanceMethods( | 130 gOriginalInitIMP = ObjcEvilDoers::SwizzleImplementedInstanceMethods( |
128 [NSException class], | 131 [NSException class], |
129 @selector(initWithName:reason:userInfo:), | 132 @selector(initWithName:reason:userInfo:), |
130 @selector(chromeInitWithName:reason:userInfo:)); | 133 @selector(chromeInitWithName:reason:userInfo:)); |
131 return YES; | 134 return YES; |
132 } | 135 } |
133 | 136 |
134 } // namespace | 137 } // namespace |
135 | 138 |
136 @implementation CrApplication | 139 @implementation BrowserCrApplication |
137 | 140 |
138 - init { | 141 - init { |
139 // TODO(shess): Push this somewhere where it can apply to the plugin | |
140 // and renderer processes, and where it can intercept uncaught | |
141 // exceptions. | |
142 DCHECK(SwizzleNSExceptionInit()); | 142 DCHECK(SwizzleNSExceptionInit()); |
143 return [super init]; | 143 return [super init]; |
144 } | 144 } |
145 | 145 |
146 // -terminate: is the entry point for orderly "quit" operations in Cocoa. | 146 // -terminate: is the entry point for orderly "quit" operations in Cocoa. |
147 // This includes the application menu's quit menu item and keyboard | 147 // This includes the application menu's quit menu item and keyboard |
148 // equivalent, the application's dock icon menu's quit menu item, "quit" (not | 148 // equivalent, the application's dock icon menu's quit menu item, "quit" (not |
149 // "force quit") in the Activity Monitor, and quits triggered by user logout | 149 // "force quit") in the Activity Monitor, and quits triggered by user logout |
150 // and system restart and shutdown. | 150 // and system restart and shutdown. |
151 // | 151 // |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 NSString* actionString = NSStringFromSelector(anAction); | 237 NSString* actionString = NSStringFromSelector(anAction); |
238 NSString* value = | 238 NSString* value = |
239 [NSString stringWithFormat:@"%@ tag %d sending %@ to %p", | 239 [NSString stringWithFormat:@"%@ tag %d sending %@ to %p", |
240 [sender className], tag, actionString, aTarget]; | 240 [sender className], tag, actionString, aTarget]; |
241 | 241 |
242 ScopedCrashKey key(kActionKey, value); | 242 ScopedCrashKey key(kActionKey, value); |
243 return [super sendAction:anAction to:aTarget from:sender]; | 243 return [super sendAction:anAction to:aTarget from:sender]; |
244 } | 244 } |
245 | 245 |
246 - (void)sendEvent:(NSEvent*)event { | 246 - (void)sendEvent:(NSEvent*)event { |
| 247 chrome_application_mac::ScopedSendingEvent scoper(self); |
247 // The superclass's |sendEvent:| sends keyboard events to the menu and the key | 248 // The superclass's |sendEvent:| sends keyboard events to the menu and the key |
248 // view loop before dispatching them to |keyDown:|. Since we want to send keys | 249 // view loop before dispatching them to |keyDown:|. Since we want to send keys |
249 // to the renderer before sending them to the menu, and we never want them to | 250 // to the renderer before sending them to the menu, and we never want them to |
250 // the kev view loop when the web is focussed, we change this behavior. | 251 // the kev view loop when the web is focussed, we change this behavior. |
251 if ([[self keyWindow] | 252 if ([[self keyWindow] |
252 isKindOfClass:[ChromeEventProcessingWindow class]]) { | 253 isKindOfClass:[ChromeEventProcessingWindow class]]) { |
253 if ([static_cast<ChromeEventProcessingWindow*>([self keyWindow]) | 254 if ([static_cast<ChromeEventProcessingWindow*>([self keyWindow]) |
254 shortcircuitEvent:event]) | 255 shortcircuitEvent:event]) |
255 return; | 256 return; |
256 } | 257 } |
257 | 258 |
258 [super sendEvent:event]; | 259 [super sendEvent:event]; |
259 } | 260 } |
260 | 261 |
261 // NSExceptions which are caught by the event loop are logged here. | 262 // NSExceptions which are caught by the event loop are logged here. |
262 // NSException uses setjmp/longjmp, which can be very bad for C++, so | 263 // NSException uses setjmp/longjmp, which can be very bad for C++, so |
263 // we attempt to track and report them. | 264 // we attempt to track and report them. |
264 - (void)reportException:(NSException *)anException { | 265 - (void)reportException:(NSException *)anException { |
265 // If we throw an exception in this code, we can create an infinite | 266 // If we throw an exception in this code, we can create an infinite |
266 // loop. If we throw out of the if() without resetting | 267 // loop. If we throw out of the if() without resetting |
267 // |reportException|, we'll stop reporting exceptions for this run. | 268 // |reportException|, we'll stop reporting exceptions for this run. |
268 static BOOL reportingException = NO; | 269 static BOOL reportingException = NO; |
269 DCHECK(!reportingException); | 270 DCHECK(!reportingException); |
270 if (!reportingException) { | 271 if (!reportingException) { |
271 reportingException = YES; | 272 reportingException = YES; |
272 CrApplicationNSException::RecordExceptionWithUma(anException); | 273 chrome_browser_application_mac::RecordExceptionWithUma(anException); |
273 | 274 |
274 // Store some human-readable information in breakpad keys in case | 275 // Store some human-readable information in breakpad keys in case |
275 // there is a crash. Since breakpad does not provide infinite | 276 // there is a crash. Since breakpad does not provide infinite |
276 // storage, we track two exceptions. The first exception thrown | 277 // storage, we track two exceptions. The first exception thrown |
277 // is tracked because it may be the one which caused the system to | 278 // is tracked because it may be the one which caused the system to |
278 // go off the rails. The last exception thrown is tracked because | 279 // go off the rails. The last exception thrown is tracked because |
279 // it may be the one most directly associated with the crash. | 280 // it may be the one most directly associated with the crash. |
280 static const NSString* kFirstExceptionKey = @"firstexception"; | 281 static const NSString* kFirstExceptionKey = @"firstexception"; |
281 static BOOL trackedFirstException = NO; | 282 static BOOL trackedFirstException = NO; |
282 static const NSString* kLastExceptionKey = @"lastexception"; | 283 static const NSString* kLastExceptionKey = @"lastexception"; |
(...skipping 16 matching lines...) Expand all Loading... |
299 SetCrashKeyValue(kLastExceptionKey, value); | 300 SetCrashKeyValue(kLastExceptionKey, value); |
300 } | 301 } |
301 | 302 |
302 reportingException = NO; | 303 reportingException = NO; |
303 } | 304 } |
304 | 305 |
305 [super reportException:anException]; | 306 [super reportException:anException]; |
306 } | 307 } |
307 | 308 |
308 @end | 309 @end |
309 | |
310 namespace CrApplicationCC { | |
311 | |
312 void Terminate() { | |
313 [NSApp terminate:nil]; | |
314 } | |
315 | |
316 } // namespace CrApplicationCC | |
OLD | NEW |