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

Side by Side Diff: chrome/browser/chrome_browser_application_mac.mm

Issue 1212093002: [Mac] Redo NSException handling, and generate better stacks for C++ exceptions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Align stack 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
« no previous file with comments | « base/message_loop/message_pump_mac.mm ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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_browser_application_mac.h" 5 #import "chrome/browser/chrome_browser_application_mac.h"
6 6
7 #include <objc/objc-exception.h>
8
7 #import "base/auto_reset.h" 9 #import "base/auto_reset.h"
8 #include "base/command_line.h" 10 #include "base/command_line.h"
9 #include "base/debug/crash_logging.h" 11 #include "base/debug/crash_logging.h"
10 #include "base/debug/stack_trace.h" 12 #include "base/debug/stack_trace.h"
11 #import "base/logging.h" 13 #import "base/logging.h"
14 #include "base/mac/call_with_eh_frame.h"
12 #import "base/mac/scoped_nsexception_enabler.h" 15 #import "base/mac/scoped_nsexception_enabler.h"
13 #import "base/mac/scoped_nsobject.h" 16 #import "base/mac/scoped_nsobject.h"
14 #import "base/mac/scoped_objc_class_swizzler.h" 17 #import "base/mac/scoped_objc_class_swizzler.h"
15 #import "base/metrics/histogram.h" 18 #import "base/metrics/histogram.h"
16 #include "base/profiler/scoped_tracker.h" 19 #include "base/profiler/scoped_tracker.h"
17 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
18 #import "base/strings/sys_string_conversions.h" 21 #import "base/strings/sys_string_conversions.h"
19 #import "chrome/browser/app_controller_mac.h" 22 #import "chrome/browser/app_controller_mac.h"
20 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" 23 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
21 #include "chrome/common/chrome_switches.h" 24 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/crash_keys.h" 25 #include "chrome/common/crash_keys.h"
23 #import "chrome/common/mac/objc_zombie.h" 26 #import "chrome/common/mac/objc_zombie.h"
24 #include "content/public/browser/browser_accessibility_state.h" 27 #include "content/public/browser/browser_accessibility_state.h"
25 #include "content/public/browser/render_view_host.h" 28 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/web_contents.h" 29 #include "content/public/browser/web_contents.h"
27 30
28 namespace {
29
30 // Tracking for cases being hit by -crInitWithName:reason:userInfo:.
31 enum ExceptionEventType {
32 EXCEPTION_ACCESSIBILITY = 0,
33 EXCEPTION_MENU_ITEM_BOUNDS_CHECK,
34 EXCEPTION_VIEW_NOT_IN_WINDOW,
35 EXCEPTION_NSURL_INIT_NIL,
36 EXCEPTION_NSDATADETECTOR_NIL_STRING,
37 EXCEPTION_NSREGULAREXPRESSION_NIL_STRING,
38
39 // Always keep this at the end.
40 EXCEPTION_MAX,
41 };
42
43 void RecordExceptionEvent(ExceptionEventType event_type) {
44 UMA_HISTOGRAM_ENUMERATION("OSX.ExceptionHandlerEvents",
45 event_type, EXCEPTION_MAX);
46 }
47
48 } // namespace
49
50 // The implementation of NSExceptions break various assumptions in the
51 // Chrome code. This category defines a replacement for
52 // -initWithName:reason:userInfo: for purposes of forcing a break in
53 // the debugger when an exception is raised. -raise sounds more
54 // obvious to intercept, but it doesn't catch the original throw
55 // because the objc runtime doesn't use it.
56 @interface NSException (CrNSExceptionSwizzle)
57 - (id)crInitWithName:(NSString*)aName
58 reason:(NSString*)aReason
59 userInfo:(NSDictionary*)someUserInfo;
60 @end
61
62 static IMP gOriginalInitIMP = NULL;
63
64 @implementation NSException (CrNSExceptionSwizzle)
65 - (id)crInitWithName:(NSString*)aName
66 reason:(NSString*)aReason
67 userInfo:(NSDictionary*)someUserInfo {
68 // Method only called when swizzled.
69 DCHECK(_cmd == @selector(initWithName:reason:userInfo:));
70 DCHECK(gOriginalInitIMP);
71
72 // Parts of Cocoa rely on creating and throwing exceptions. These are not
73 // worth bugging-out over. It is very important that there be zero chance that
74 // any Chromium code is on the stack; these must be created by Apple code and
75 // then immediately consumed by Apple code.
76 static NSString* const kAcceptableNSExceptionNames[] = {
77 // If an object does not support an accessibility attribute, this will
78 // get thrown.
79 NSAccessibilityException,
80 };
81
82 BOOL found = NO;
83 for (size_t i = 0; i < arraysize(kAcceptableNSExceptionNames); ++i) {
84 if (aName == kAcceptableNSExceptionNames[i]) {
85 found = YES;
86 RecordExceptionEvent(EXCEPTION_ACCESSIBILITY);
87 break;
88 }
89 }
90
91 if (!found) {
92 // Update breakpad with the exception info.
93 std::string value = base::StringPrintf("%s reason %s",
94 [aName UTF8String], [aReason UTF8String]);
95 base::debug::SetCrashKeyValue(crash_keys::mac::kNSException, value);
96 base::debug::SetCrashKeyToStackTrace(crash_keys::mac::kNSExceptionTrace,
97 base::debug::StackTrace());
98
99 // Force crash for selected exceptions to generate crash dumps.
100 BOOL fatal = NO;
101 if (aName == NSInternalInconsistencyException) {
102 NSString* const kNSMenuItemArrayBoundsCheck =
103 @"Invalid parameter not satisfying: (index >= 0) && "
104 @"(index < [_itemArray count])";
105 if ([aReason isEqualToString:kNSMenuItemArrayBoundsCheck]) {
106 RecordExceptionEvent(EXCEPTION_MENU_ITEM_BOUNDS_CHECK);
107 fatal = YES;
108 }
109
110 NSString* const kNoWindowCheck = @"View is not in any window";
111 if ([aReason isEqualToString:kNoWindowCheck]) {
112 RecordExceptionEvent(EXCEPTION_VIEW_NOT_IN_WINDOW);
113 fatal = YES;
114 }
115 }
116
117 // Mostly "unrecognized selector sent to (instance|class)". A
118 // very small number of things like inappropriate nil being passed.
119 if (aName == NSInvalidArgumentException) {
120 fatal = YES;
121
122 // TODO(shess): http://crbug.com/85463 throws this exception
123 // from ImageKit. Our code is not on the stack, so it needs to
124 // be whitelisted for now.
125 NSString* const kNSURLInitNilCheck =
126 @"*** -[NSURL initFileURLWithPath:isDirectory:]: "
127 @"nil string parameter";
128 if ([aReason isEqualToString:kNSURLInitNilCheck]) {
129 RecordExceptionEvent(EXCEPTION_NSURL_INIT_NIL);
130 fatal = NO;
131 }
132
133 // <http://crbug.com/316759> OSX 10.9 fails trying to extract
134 // structure from a string.
135 NSString* const kNSDataDetectorNilCheck =
136 @"*** -[NSDataDetector enumerateMatchesInString:"
137 @"options:range:usingBlock:]: nil argument";
138 if ([aReason isEqualToString:kNSDataDetectorNilCheck]) {
139 RecordExceptionEvent(EXCEPTION_NSDATADETECTOR_NIL_STRING);
140 fatal = NO;
141 }
142
143 // <http://crbug.com/466076> OSX 10.10 moved the method.
144 NSString* const kNSRegularExpressionNilCheck =
145 @"*** -[NSRegularExpression enumerateMatchesInString:"
146 @"options:range:usingBlock:]: nil argument";
147 if ([aReason isEqualToString:kNSRegularExpressionNilCheck]) {
148 RecordExceptionEvent(EXCEPTION_NSREGULAREXPRESSION_NIL_STRING);
149 fatal = NO;
150 }
151 }
152
153 // Dear reader: Something you just did provoked an NSException.
154 // NSException is implemented in terms of setjmp()/longjmp(),
155 // which does poor things when combined with C++ scoping
156 // (destructors are skipped). Chrome should be NSException-free,
157 // please check your backtrace and see if you can't file a bug
158 // with a repro case.
159 const bool allow = base::mac::GetNSExceptionsAllowed();
160 if (fatal && !allow) {
161 LOG(FATAL) << "Someone is trying to raise an exception! "
162 << value;
163 } else {
164 // Make sure that developers see when their code throws
165 // exceptions.
166 DCHECK(allow) << "Someone is trying to raise an exception! "
167 << value;
168 }
169 }
170
171 // Forward to the original version.
172 return gOriginalInitIMP(self, _cmd, aName, aReason, someUserInfo);
173 }
174 @end
175
176 namespace chrome_browser_application_mac { 31 namespace chrome_browser_application_mac {
177 32
178 // Maximum number of known named exceptions we'll support. There is 33 // Maximum number of known named exceptions we'll support. There is
179 // no central registration, but I only find about 75 possibilities in 34 // no central registration, but I only find about 75 possibilities in
180 // the system frameworks, and many of them are probably not 35 // the system frameworks, and many of them are probably not
181 // interesting to track in aggregate (those relating to distributed 36 // interesting to track in aggregate (those relating to distributed
182 // objects, for instance). 37 // objects, for instance).
183 const size_t kKnownNSExceptionCount = 25; 38 const size_t kKnownNSExceptionCount = 25;
184 39
185 const size_t kUnknownNSException = kKnownNSExceptionCount; 40 const size_t kUnknownNSException = kKnownNSExceptionCount;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 } 77 }
223 } 78 }
224 return kUnknownNSException; 79 return kUnknownNSException;
225 } 80 }
226 81
227 void RecordExceptionWithUma(NSException* exception) { 82 void RecordExceptionWithUma(NSException* exception) {
228 UMA_HISTOGRAM_ENUMERATION("OSX.NSException", 83 UMA_HISTOGRAM_ENUMERATION("OSX.NSException",
229 BinForException(exception), kUnknownNSException); 84 BinForException(exception), kUnknownNSException);
230 } 85 }
231 86
87 namespace {
88
89 objc_exception_preprocessor g_next_preprocessor = nullptr;
90
91 id ExceptionPreprocessor(id exception) {
92 static bool seen_first_exception = false;
93
94 RecordExceptionWithUma(exception);
95
96 const char* const kExceptionKey =
97 seen_first_exception ? crash_keys::mac::kLastNSException
98 : crash_keys::mac::kFirstNSException;
99 NSString* value = [NSString stringWithFormat:@"%@ reason %@",
100 [exception name], [exception reason]];
101 base::debug::SetCrashKeyValue(kExceptionKey, [value UTF8String]);
102
103 const char* const kExceptionTraceKey =
104 seen_first_exception ? crash_keys::mac::kLastNSExceptionTrace
105 : crash_keys::mac::kFirstNSExceptionTrace;
106 // This exception preprocessor runs prior to the one in libobjc, which sets
107 // the -[NSException callStackReturnAddresses].
108 base::debug::SetCrashKeyToStackTrace(kExceptionTraceKey,
109 base::debug::StackTrace());
110
111 seen_first_exception = true;
112
113 // Forward to the original version.
114 if (g_next_preprocessor)
115 return g_next_preprocessor(exception);
116 return exception;
117 }
118
119 } // namespace
120
232 void RegisterBrowserCrApp() { 121 void RegisterBrowserCrApp() {
233 [BrowserCrApplication sharedApplication]; 122 [BrowserCrApplication sharedApplication];
234 }; 123 };
235 124
236 void Terminate() { 125 void Terminate() {
237 [NSApp terminate:nil]; 126 [NSApp terminate:nil];
238 } 127 }
239 128
240 void CancelTerminate() { 129 void CancelTerminate() {
241 [NSApp cancelTerminate:nil]; 130 [NSApp cancelTerminate:nil];
242 } 131 }
243 132
244 } // namespace chrome_browser_application_mac 133 } // namespace chrome_browser_application_mac
245 134
246 namespace {
247
248 void SwizzleInit() {
249 // Do-nothing wrapper so that we can arrange to only swizzle
250 // -[NSException raise] when DCHECK() is turned on (as opposed to
251 // replicating the preprocess logic which turns DCHECK() on).
252 CR_DEFINE_STATIC_LOCAL(base::mac::ScopedObjCClassSwizzler,
253 swizzle_exception,
254 ([NSException class],
255 @selector(initWithName:reason:userInfo:),
256 @selector(crInitWithName:reason:userInfo:)));
257 gOriginalInitIMP = swizzle_exception.GetOriginalImplementation();
258 }
259
260 } // namespace
261
262 // These methods are being exposed for the purposes of overriding. 135 // These methods are being exposed for the purposes of overriding.
263 // Used to determine when a Panel window can become the key window. 136 // Used to determine when a Panel window can become the key window.
264 @interface NSApplication (PanelsCanBecomeKey) 137 @interface NSApplication (PanelsCanBecomeKey)
265 - (void)_cycleWindowsReversed:(BOOL)arg1; 138 - (void)_cycleWindowsReversed:(BOOL)arg1;
266 - (id)_removeWindow:(NSWindow*)window; 139 - (id)_removeWindow:(NSWindow*)window;
267 - (id)_setKeyWindow:(NSWindow*)window; 140 - (id)_setKeyWindow:(NSWindow*)window;
268 @end 141 @end
269 142
270 @interface BrowserCrApplication (PrivateInternal) 143 @interface BrowserCrApplication (PrivateInternal)
271 144
272 // This must be called under the protection of previousKeyWindowsLock_. 145 // This must be called under the protection of previousKeyWindowsLock_.
273 - (void)removePreviousKeyWindow:(NSWindow*)window; 146 - (void)removePreviousKeyWindow:(NSWindow*)window;
274 147
275 @end 148 @end
276 149
277 @implementation BrowserCrApplication 150 @implementation BrowserCrApplication
278 151
279 + (void)initialize { 152 + (void)initialize {
280 // Turn all deallocated Objective-C objects into zombies, keeping 153 // Turn all deallocated Objective-C objects into zombies, keeping
281 // the most recent 10,000 of them on the treadmill. 154 // the most recent 10,000 of them on the treadmill.
282 ObjcEvilDoers::ZombieEnable(true, 10000); 155 ObjcEvilDoers::ZombieEnable(true, 10000);
156
157 if (!chrome_browser_application_mac::g_next_preprocessor) {
158 chrome_browser_application_mac::g_next_preprocessor =
159 objc_setExceptionPreprocessor(
160 &chrome_browser_application_mac::ExceptionPreprocessor);
161 }
283 } 162 }
284 163
285 - (id)init { 164 - (id)init {
286 SwizzleInit();
287 self = [super init]; 165 self = [super init];
288 166
289 // Sanity check to alert if overridden methods are not supported. 167 // Sanity check to alert if overridden methods are not supported.
290 DCHECK([NSApplication 168 DCHECK([NSApplication
291 instancesRespondToSelector:@selector(_cycleWindowsReversed:)]); 169 instancesRespondToSelector:@selector(_cycleWindowsReversed:)]);
292 DCHECK([NSApplication 170 DCHECK([NSApplication
293 instancesRespondToSelector:@selector(_removeWindow:)]); 171 instancesRespondToSelector:@selector(_removeWindow:)]);
294 DCHECK([NSApplication 172 DCHECK([NSApplication
295 instancesRespondToSelector:@selector(_setKeyWindow:)]); 173 instancesRespondToSelector:@selector(_setKeyWindow:)]);
296 174
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 342
465 - (BOOL)isHandlingSendEvent { 343 - (BOOL)isHandlingSendEvent {
466 return handlingSendEvent_; 344 return handlingSendEvent_;
467 } 345 }
468 346
469 - (void)setHandlingSendEvent:(BOOL)handlingSendEvent { 347 - (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
470 handlingSendEvent_ = handlingSendEvent; 348 handlingSendEvent_ = handlingSendEvent;
471 } 349 }
472 350
473 - (void)sendEvent:(NSEvent*)event { 351 - (void)sendEvent:(NSEvent*)event {
474 // tracked_objects::ScopedTracker does not support parameterized 352 base::mac::CallWithEHFrame(^{
475 // instrumentations, so a big switch with each bunch instrumented is required. 353 // tracked_objects::ScopedTracker does not support parameterized
476 switch (event.type) { 354 // instrumentations, so a big switch with each bunch instrumented is
477 case NSLeftMouseDown: 355 // required.
478 case NSRightMouseDown: { 356 switch (event.type) {
479 // In kiosk mode, we want to prevent context menus from appearing, 357 case NSLeftMouseDown:
480 // so simply discard menu-generating events instead of passing them along. 358 case NSRightMouseDown: {
481 bool kioskMode = base::CommandLine::ForCurrentProcess()->HasSwitch( 359 // In kiosk mode, we want to prevent context menus from appearing,
482 switches::kKioskMode); 360 // so simply discard menu-generating events instead of passing them
483 bool ctrlDown = [event modifierFlags] & NSControlKeyMask; 361 // along.
484 if (kioskMode && ([event type] == NSRightMouseDown || ctrlDown)) 362 bool kioskMode = base::CommandLine::ForCurrentProcess()->HasSwitch(
363 switches::kKioskMode);
364 bool ctrlDown = [event modifierFlags] & NSControlKeyMask;
365 if (kioskMode && ([event type] == NSRightMouseDown || ctrlDown))
366 break;
367 }
368 // FALL THROUGH
369 case NSLeftMouseUp:
370 case NSRightMouseUp:
371 case NSMouseMoved:
372 case NSLeftMouseDragged:
373 case NSRightMouseDragged:
374 case NSMouseEntered:
375 case NSMouseExited:
376 case NSOtherMouseDown:
377 case NSOtherMouseUp:
378 case NSOtherMouseDragged: {
379 tracked_objects::ScopedTracker tracking_profile(
380 FROM_HERE_WITH_EXPLICIT_FUNCTION(
381 "463272 -[BrowserCrApplication sendEvent:] Mouse"));
382 base::mac::ScopedSendingEvent sendingEventScoper;
383 [super sendEvent:event];
485 break; 384 break;
385 }
386
387 case NSKeyDown:
388 case NSKeyUp: {
389 tracked_objects::ScopedTracker tracking_profile(
390 FROM_HERE_WITH_EXPLICIT_FUNCTION(
391 "463272 -[BrowserCrApplication sendEvent:] Key"));
392 base::mac::ScopedSendingEvent sendingEventScoper;
393 [super sendEvent:event];
394 break;
395 }
396
397 case NSScrollWheel: {
398 tracked_objects::ScopedTracker tracking_profile(
399 FROM_HERE_WITH_EXPLICIT_FUNCTION(
400 "463272 -[BrowserCrApplication sendEvent:] ScrollWheel"));
401 base::mac::ScopedSendingEvent sendingEventScoper;
402 [super sendEvent:event];
403 break;
404 }
405
406 case NSEventTypeGesture:
407 case NSEventTypeMagnify:
408 case NSEventTypeSwipe:
409 case NSEventTypeRotate:
410 case NSEventTypeBeginGesture:
411 case NSEventTypeEndGesture: {
412 tracked_objects::ScopedTracker tracking_profile(
413 FROM_HERE_WITH_EXPLICIT_FUNCTION(
414 "463272 -[BrowserCrApplication sendEvent:] Gesture"));
415 base::mac::ScopedSendingEvent sendingEventScoper;
416 [super sendEvent:event];
417 break;
418 }
419
420 case NSAppKitDefined: {
421 tracked_objects::ScopedTracker tracking_profile(
422 FROM_HERE_WITH_EXPLICIT_FUNCTION(
423 "463272 -[BrowserCrApplication sendEvent:] AppKit"));
424 base::mac::ScopedSendingEvent sendingEventScoper;
425 [super sendEvent:event];
426 break;
427 }
428
429 case NSSystemDefined: {
430 tracked_objects::ScopedTracker tracking_profile(
431 FROM_HERE_WITH_EXPLICIT_FUNCTION(
432 "463272 -[BrowserCrApplication sendEvent:] System"));
433 base::mac::ScopedSendingEvent sendingEventScoper;
434 [super sendEvent:event];
435 break;
436 }
437
438 default: {
439 tracked_objects::ScopedTracker tracking_profile(
440 FROM_HERE_WITH_EXPLICIT_FUNCTION(
441 "463272 -[BrowserCrApplication sendEvent:] Other"));
442 base::mac::ScopedSendingEvent sendingEventScoper;
443 [super sendEvent:event];
444 }
486 } 445 }
487 // FALL THROUGH 446 });
488 case NSLeftMouseUp:
489 case NSRightMouseUp:
490 case NSMouseMoved:
491 case NSLeftMouseDragged:
492 case NSRightMouseDragged:
493 case NSMouseEntered:
494 case NSMouseExited:
495 case NSOtherMouseDown:
496 case NSOtherMouseUp:
497 case NSOtherMouseDragged: {
498 tracked_objects::ScopedTracker tracking_profile(
499 FROM_HERE_WITH_EXPLICIT_FUNCTION(
500 "463272 -[BrowserCrApplication sendEvent:] Mouse"));
501 base::mac::ScopedSendingEvent sendingEventScoper;
502 [super sendEvent:event];
503 break;
504 }
505
506 case NSKeyDown:
507 case NSKeyUp: {
508 tracked_objects::ScopedTracker tracking_profile(
509 FROM_HERE_WITH_EXPLICIT_FUNCTION(
510 "463272 -[BrowserCrApplication sendEvent:] Key"));
511 base::mac::ScopedSendingEvent sendingEventScoper;
512 [super sendEvent:event];
513 break;
514 }
515
516 case NSScrollWheel: {
517 tracked_objects::ScopedTracker tracking_profile(
518 FROM_HERE_WITH_EXPLICIT_FUNCTION(
519 "463272 -[BrowserCrApplication sendEvent:] ScrollWheel"));
520 base::mac::ScopedSendingEvent sendingEventScoper;
521 [super sendEvent:event];
522 break;
523 }
524
525 case NSEventTypeGesture:
526 case NSEventTypeMagnify:
527 case NSEventTypeSwipe:
528 case NSEventTypeRotate:
529 case NSEventTypeBeginGesture:
530 case NSEventTypeEndGesture: {
531 tracked_objects::ScopedTracker tracking_profile(
532 FROM_HERE_WITH_EXPLICIT_FUNCTION(
533 "463272 -[BrowserCrApplication sendEvent:] Gesture"));
534 base::mac::ScopedSendingEvent sendingEventScoper;
535 [super sendEvent:event];
536 break;
537 }
538
539 case NSAppKitDefined: {
540 tracked_objects::ScopedTracker tracking_profile(
541 FROM_HERE_WITH_EXPLICIT_FUNCTION(
542 "463272 -[BrowserCrApplication sendEvent:] AppKit"));
543 base::mac::ScopedSendingEvent sendingEventScoper;
544 [super sendEvent:event];
545 break;
546 }
547
548 case NSSystemDefined: {
549 tracked_objects::ScopedTracker tracking_profile(
550 FROM_HERE_WITH_EXPLICIT_FUNCTION(
551 "463272 -[BrowserCrApplication sendEvent:] System"));
552 base::mac::ScopedSendingEvent sendingEventScoper;
553 [super sendEvent:event];
554 break;
555 }
556
557 default: {
558 tracked_objects::ScopedTracker tracking_profile(
559 FROM_HERE_WITH_EXPLICIT_FUNCTION(
560 "463272 -[BrowserCrApplication sendEvent:] Other"));
561 base::mac::ScopedSendingEvent sendingEventScoper;
562 [super sendEvent:event];
563 }
564 }
565 }
566
567 // NSExceptions which are caught by the event loop are logged here.
568 // NSException uses setjmp/longjmp, which can be very bad for C++, so
569 // we attempt to track and report them.
570 - (void)reportException:(NSException *)anException {
571 // If we throw an exception in this code, we can create an infinite
572 // loop. If we throw out of the if() without resetting
573 // |reportException|, we'll stop reporting exceptions for this run.
574 static BOOL reportingException = NO;
575 DCHECK(!reportingException);
576 if (!reportingException) {
577 reportingException = YES;
578 chrome_browser_application_mac::RecordExceptionWithUma(anException);
579
580 // http://crbug.com/45928 is a bug about needing to double-close
581 // windows sometimes. One theory is that |-isHandlingSendEvent|
582 // gets latched to always return |YES|. Since scopers are used to
583 // manipulate that value, that should not be possible. One way to
584 // sidestep scopers is setjmp/longjmp (see above). The following
585 // is to "fix" this while the more fundamental concern is
586 // addressed elsewhere.
587 [self setHandlingSendEvent:NO];
588
589 // If |ScopedNSExceptionEnabler| is used to allow exceptions, and an
590 // uncaught exception is thrown, it will throw past all of the scopers.
591 // Reset the flag so that future exceptions are not masked.
592 base::mac::SetNSExceptionsAllowed(false);
593
594 // Store some human-readable information in breakpad keys in case
595 // there is a crash. Since breakpad does not provide infinite
596 // storage, we track two exceptions. The first exception thrown
597 // is tracked because it may be the one which caused the system to
598 // go off the rails. The last exception thrown is tracked because
599 // it may be the one most directly associated with the crash.
600 static BOOL trackedFirstException = NO;
601
602 const char* const kExceptionKey =
603 trackedFirstException ? crash_keys::mac::kLastNSException
604 : crash_keys::mac::kFirstNSException;
605 NSString* value = [NSString stringWithFormat:@"%@ reason %@",
606 [anException name], [anException reason]];
607 base::debug::SetCrashKeyValue(kExceptionKey, [value UTF8String]);
608
609 // Encode the callstack from point of throw.
610 // TODO(shess): Our swizzle plus the 23-frame limit plus Cocoa
611 // overhead may make this less than useful. If so, perhaps skip
612 // some items and/or use two keys.
613 const char* const kExceptionBtKey =
614 trackedFirstException ? crash_keys::mac::kLastNSExceptionTrace
615 : crash_keys::mac::kFirstNSExceptionTrace;
616 NSArray* addressArray = [anException callStackReturnAddresses];
617 NSUInteger addressCount = [addressArray count];
618 if (addressCount) {
619 // SetCrashKeyFromAddresses() only encodes 23, so that's a natural limit.
620 const NSUInteger kAddressCountMax = 23;
621 void* addresses[kAddressCountMax];
622 if (addressCount > kAddressCountMax)
623 addressCount = kAddressCountMax;
624
625 for (NSUInteger i = 0; i < addressCount; ++i) {
626 addresses[i] = reinterpret_cast<void*>(
627 [[addressArray objectAtIndex:i] unsignedIntegerValue]);
628 }
629 base::debug::SetCrashKeyFromAddresses(
630 kExceptionBtKey, addresses, static_cast<size_t>(addressCount));
631 } else {
632 base::debug::ClearCrashKey(kExceptionBtKey);
633 }
634 trackedFirstException = YES;
635
636 reportingException = NO;
637 }
638
639 [super reportException:anException];
640 } 447 }
641 448
642 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { 449 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
643 // This is an undocument attribute that's set when VoiceOver is turned on/off. 450 // This is an undocument attribute that's set when VoiceOver is turned on/off.
644 if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) { 451 if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) {
645 content::BrowserAccessibilityState* accessibility_state = 452 content::BrowserAccessibilityState* accessibility_state =
646 content::BrowserAccessibilityState::GetInstance(); 453 content::BrowserAccessibilityState::GetInstance();
647 if ([value intValue] == 1) 454 if ([value intValue] == 1)
648 accessibility_state->OnScreenReaderDetected(); 455 accessibility_state->OnScreenReaderDetected();
649 else 456 else
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
696 std::vector<NSWindow*>::iterator window_iterator = 503 std::vector<NSWindow*>::iterator window_iterator =
697 std::find(previousKeyWindows_.begin(), 504 std::find(previousKeyWindows_.begin(),
698 previousKeyWindows_.end(), 505 previousKeyWindows_.end(),
699 window); 506 window);
700 if (window_iterator != previousKeyWindows_.end()) { 507 if (window_iterator != previousKeyWindows_.end()) {
701 previousKeyWindows_.erase(window_iterator); 508 previousKeyWindows_.erase(window_iterator);
702 } 509 }
703 } 510 }
704 511
705 @end 512 @end
OLDNEW
« no previous file with comments | « base/message_loop/message_pump_mac.mm ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698