| 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 |