mac: Enable ARC in libcef (fixes #3496)

Also enables debugging of zombie Objective-C objects.
This commit is contained in:
Marshall Greenblatt 2023-05-05 14:17:14 +03:00
parent e5c4b27366
commit e5334a5a18
10 changed files with 105 additions and 70 deletions

View File

@ -1156,6 +1156,8 @@ source_set("libcef_static") {
"//chrome/app/chrome_main_mac.h", "//chrome/app/chrome_main_mac.h",
"//chrome/app/chrome_main_mac.mm", "//chrome/app/chrome_main_mac.mm",
] ]
configs += [ "//build/config/compiler:enable_arc" ]
} }
if (ozone_platform_x11) { if (ozone_platform_x11) {
@ -1602,6 +1604,7 @@ if (is_mac) {
configs += [ configs += [
":libcef_autogen_config", ":libcef_autogen_config",
"//build/config/compiler:enable_arc",
] ]
# We don't link the framework so just use the path from the main executable. # We don't link the framework so just use the path from the main executable.

View File

@ -7,6 +7,12 @@
#include "libcef/browser/native/browser_platform_delegate_native.h" #include "libcef/browser/native/browser_platform_delegate_native.h"
#if defined(__OBJC__)
@class CefWindowDelegate;
#else
class CefWindowDelegate;
#endif
namespace content { namespace content {
class RenderWidgetHostViewMac; class RenderWidgetHostViewMac;
} }
@ -67,7 +73,9 @@ class CefBrowserPlatformDelegateNativeMac
content::RenderWidgetHostViewMac* GetHostView() const; content::RenderWidgetHostViewMac* GetHostView() const;
// True if the host window has been created. // True if the host window has been created.
bool host_window_created_; bool host_window_created_ = false;
CefWindowDelegate* __strong window_delegate_;
}; };
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_MAC_H_ #endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_MAC_H_

View File

@ -7,6 +7,7 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h> #import <CoreServices/CoreServices.h>
#include "include/internal/cef_types_mac.h"
#include "libcef/browser/alloy/alloy_browser_host_impl.h" #include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "libcef/browser/context.h" #include "libcef/browser/context.h"
#include "libcef/browser/native/javascript_dialog_runner_mac.h" #include "libcef/browser/native/javascript_dialog_runner_mac.h"
@ -28,6 +29,10 @@
#include "ui/events/keycodes/keyboard_codes_posix.h" #include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Wrapper NSView for the native view. Necessary to destroy the browser when // Wrapper NSView for the native view. Necessary to destroy the browser when
// the view is deleted. // the view is deleted.
@interface CefBrowserHostView : NSView { @interface CefBrowserHostView : NSView {
@ -49,8 +54,6 @@
// PlatformCreateWindow(). // PlatformCreateWindow().
static_cast<AlloyBrowserHostImpl*>(browser_)->WindowDestroyed(); static_cast<AlloyBrowserHostImpl*>(browser_)->WindowDestroyed();
} }
[super dealloc];
} }
@end @end
@ -59,7 +62,7 @@
@interface CefWindowDelegate : NSObject <NSWindowDelegate> { @interface CefWindowDelegate : NSObject <NSWindowDelegate> {
@private @private
CefBrowserHostBase* browser_; // weak CefBrowserHostBase* browser_; // weak
NSWindow* window_; NSWindow* __strong window_;
} }
- (id)initWithWindow:(NSWindow*)window andBrowser:(CefBrowserHostBase*)browser; - (id)initWithWindow:(NSWindow*)window andBrowser:(CefBrowserHostBase*)browser;
@end @end
@ -70,16 +73,12 @@
if (self = [super init]) { if (self = [super init]) {
window_ = window; window_ = window;
browser_ = browser; browser_ = browser;
[window_ setDelegate:self];
} }
return self; return self;
} }
- (void)dealloc { - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
} }
- (BOOL)windowShouldClose:(id)window { - (BOOL)windowShouldClose:(id)window {
@ -88,6 +87,11 @@
return NO; return NO;
} }
// For an NSWindow object, the default is to be released on |close|. We
// instead want it to remain valid until all strong references are released
// via |cleanup:| and |BrowserDestroyed|.
((NSWindow*)window).releasedWhenClosed = NO;
// Clean ourselves up after clearing the stack of anything that might have the // Clean ourselves up after clearing the stack of anything that might have the
// window on it. // window on it.
[self performSelectorOnMainThread:@selector(cleanup:) [self performSelectorOnMainThread:@selector(cleanup:)
@ -100,7 +104,7 @@
- (void)cleanup:(id)window { - (void)cleanup:(id)window {
[window_ setDelegate:nil]; [window_ setDelegate:nil];
[self release]; window_ = nil;
} }
@end @end
@ -239,16 +243,16 @@ void GetNSBoundsInDisplay(const gfx::Rect& dip_bounds,
CefBrowserPlatformDelegateNativeMac::CefBrowserPlatformDelegateNativeMac( CefBrowserPlatformDelegateNativeMac::CefBrowserPlatformDelegateNativeMac(
const CefWindowInfo& window_info, const CefWindowInfo& window_info,
SkColor background_color) SkColor background_color)
: CefBrowserPlatformDelegateNative(window_info, background_color), : CefBrowserPlatformDelegateNative(window_info, background_color) {}
host_window_created_(false) {}
void CefBrowserPlatformDelegateNativeMac::BrowserDestroyed( void CefBrowserPlatformDelegateNativeMac::BrowserDestroyed(
CefBrowserHostBase* browser) { CefBrowserHostBase* browser) {
CefBrowserPlatformDelegateNative::BrowserDestroyed(browser); CefBrowserPlatformDelegateNative::BrowserDestroyed(browser);
if (host_window_created_) { if (host_window_created_) {
// Release the reference added in CreateHostWindow(). // Release the references added in CreateHostWindow().
browser->Release(); browser->Release();
window_delegate_ = nil;
} }
} }
@ -285,12 +289,15 @@ bool CefBrowserPlatformDelegateNativeMac::CreateHostWindow() {
defer:NO]; defer:NO];
// Create the delegate for control and browser window events. // Create the delegate for control and browser window events.
[[CefWindowDelegate alloc] initWithWindow:new_window andBrowser:browser_]; // Add a reference that will be released in BrowserDestroyed().
window_delegate_ = [[CefWindowDelegate alloc] initWithWindow:new_window
andBrowser:browser_];
[new_window setDelegate:window_delegate_];
parent_view = [new_window contentView]; parent_view = [new_window contentView];
browser_view_rect = [parent_view bounds]; browser_view_rect = [parent_view bounds];
window_info_.parent_view = parent_view; window_info_.parent_view = CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(parent_view);
// Make the content view for the window have a layer. This will make all // Make the content view for the window have a layer. This will make all
// sub-views have layers. This is necessary to ensure correct layer // sub-views have layers. This is necessary to ensure correct layer
@ -314,7 +321,6 @@ bool CefBrowserPlatformDelegateNativeMac::CreateHostWindow() {
[parent_view addSubview:browser_view]; [parent_view addSubview:browser_view];
[browser_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; [browser_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[browser_view setNeedsDisplay:YES]; [browser_view setNeedsDisplay:YES];
[browser_view release];
// Parent the WebContents to the browser view. // Parent the WebContents to the browser view.
const NSRect bounds = [browser_view bounds]; const NSRect bounds = [browser_view bounds];
@ -324,7 +330,7 @@ bool CefBrowserPlatformDelegateNativeMac::CreateHostWindow() {
[native_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; [native_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[native_view setNeedsDisplay:YES]; [native_view setNeedsDisplay:YES];
window_info_.view = browser_view; window_info_.view = CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(browser_view);
if (new_window != nil && !window_info_.hidden) { if (new_window != nil && !window_info_.hidden) {
// Show the window. // Show the window.
@ -461,7 +467,7 @@ void CefBrowserPlatformDelegate::HandleExternalProtocol(const GURL& url) {}
CefEventHandle CefBrowserPlatformDelegateNativeMac::GetEventHandle( CefEventHandle CefBrowserPlatformDelegateNativeMac::GetEventHandle(
const content::NativeWebKeyboardEvent& event) const { const content::NativeWebKeyboardEvent& event) const {
return event.os_event; return CAST_NSEVENT_TO_CEF_EVENT_HANDLE(event.os_event);
} }
std::unique_ptr<CefJavaScriptDialogRunner> std::unique_ptr<CefJavaScriptDialogRunner>
@ -507,11 +513,10 @@ CefBrowserPlatformDelegateNativeMac::TranslateWebKeyEvent(
} }
NSString* charactersIgnoringModifiers = NSString* charactersIgnoringModifiers =
[[[NSString alloc] initWithCharacters:&key_event.unmodified_character [[NSString alloc] initWithCharacters:&key_event.unmodified_character
length:1] autorelease]; length:1];
NSString* characters = NSString* characters =
[[[NSString alloc] initWithCharacters:&key_event.character [[NSString alloc] initWithCharacters:&key_event.character length:1];
length:1] autorelease];
NSEvent* synthetic_event = NSEvent* synthetic_event =
[NSEvent keyEventWithType:event_type [NSEvent keyEventWithType:event_type

View File

@ -2,11 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be found // Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file. // in the LICENSE file.
#include "include/internal/cef_types_mac.h"
#include "libcef/browser/native/cursor_util.h" #include "libcef/browser/native/cursor_util.h"
#import "base/mac/scoped_nsobject.h"
#import "ui/base/cocoa/cursor_utils.h" #import "ui/base/cocoa/cursor_utils.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace cursor_util { namespace cursor_util {
namespace { namespace {
@ -15,14 +19,16 @@ class ScopedCursorHandleImpl : public ScopedCursorHandle {
public: public:
explicit ScopedCursorHandleImpl(NSCursor* native_cursor) { explicit ScopedCursorHandleImpl(NSCursor* native_cursor) {
if (native_cursor) { if (native_cursor) {
cursor_.reset([native_cursor retain]); cursor_ = native_cursor;
} }
} }
cef_cursor_handle_t GetCursorHandle() override { return cursor_.get(); } cef_cursor_handle_t GetCursorHandle() override {
return CAST_NSCURSOR_TO_CEF_CURSOR_HANDLE(cursor_);
}
private: private:
base::scoped_nsobject<NSCursor> cursor_; NSCursor* __strong cursor_;
}; };
} // namespace } // namespace

View File

@ -10,7 +10,6 @@
#include "libcef/browser/javascript_dialog_runner.h" #include "libcef/browser/javascript_dialog_runner.h"
#include "base/functional/callback.h" #include "base/functional/callback.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#if __OBJC__ #if __OBJC__
@ -40,7 +39,7 @@ class CefJavaScriptDialogRunnerMac : public CefJavaScriptDialogRunner {
private: private:
DialogClosedCallback callback_; DialogClosedCallback callback_;
base::scoped_nsobject<CefJavaScriptDialogHelper> helper_; CefJavaScriptDialogHelper* __strong helper_;
// Must be the last member. // Must be the last member.
base::WeakPtrFactory<CefJavaScriptDialogRunnerMac> weak_ptr_factory_; base::WeakPtrFactory<CefJavaScriptDialogRunnerMac> weak_ptr_factory_;

View File

@ -12,12 +12,16 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "components/url_formatter/elide_url.h" #include "components/url_formatter/elide_url.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Helper object that receives the notification that the dialog/sheet is // Helper object that receives the notification that the dialog/sheet is
// going away. Is responsible for cleaning itself up. // going away. Is responsible for cleaning itself up.
@interface CefJavaScriptDialogHelper : NSObject <NSAlertDelegate> { @interface CefJavaScriptDialogHelper : NSObject <NSAlertDelegate> {
@private @private
base::scoped_nsobject<NSAlert> alert_; NSAlert* __strong alert_;
NSTextField* textField_; // WEAK; owned by alert_ NSTextField* __weak textField_;
// Copies of the fields in CefJavaScriptDialog because they're private. // Copies of the fields in CefJavaScriptDialog because they're private.
CefJavaScriptDialogRunner::DialogClosedCallback callback_; CefJavaScriptDialogRunner::DialogClosedCallback callback_;
@ -46,18 +50,20 @@
} }
- (NSAlert*)alert { - (NSAlert*)alert {
alert_.reset([[NSAlert alloc] init]); alert_ = [[NSAlert alloc] init];
return alert_; return alert_;
} }
- (NSTextField*)textField { - (NSTextField*)textField {
textField_ = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)]; NSTextField* textField =
[[textField_ cell] setLineBreakMode:NSLineBreakByTruncatingTail]; [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)];
[alert_ setAccessoryView:textField_]; textField.cell.lineBreakMode = NSLineBreakByTruncatingTail;
[[alert_ window] setInitialFirstResponder:textField_];
[textField_ release];
return textField_; alert_.accessoryView = textField;
alert_.window.initialFirstResponder = textField;
textField_ = textField;
return textField;
} }
- (void)alertDidEnd:(NSAlert*)alert - (void)alertDidEnd:(NSAlert*)alert
@ -70,15 +76,15 @@
bool success = returnCode == NSAlertFirstButtonReturn; bool success = returnCode == NSAlertFirstButtonReturn;
std::u16string input; std::u16string input;
if (textField_) { if (textField_) {
input = base::SysNSStringToUTF16([textField_ stringValue]); input = base::SysNSStringToUTF16(textField_.stringValue);
} }
std::move(callback_).Run(success, input); std::move(callback_).Run(success, input);
} }
- (void)cancel { - (void)cancel {
[NSApp endSheet:[alert_ window]]; [NSApp endSheet:alert_.window];
alert_.reset(); alert_ = nil;
} }
@end @end
@ -97,26 +103,26 @@ void CefJavaScriptDialogRunnerMac::Run(
const std::u16string& message_text, const std::u16string& message_text,
const std::u16string& default_prompt_text, const std::u16string& default_prompt_text,
DialogClosedCallback callback) { DialogClosedCallback callback) {
DCHECK(!helper_.get()); DCHECK(!helper_);
callback_ = std::move(callback); callback_ = std::move(callback);
bool text_field = message_type == content::JAVASCRIPT_DIALOG_TYPE_PROMPT; bool text_field = message_type == content::JAVASCRIPT_DIALOG_TYPE_PROMPT;
bool one_button = message_type == content::JAVASCRIPT_DIALOG_TYPE_ALERT; bool one_button = message_type == content::JAVASCRIPT_DIALOG_TYPE_ALERT;
helper_.reset([[CefJavaScriptDialogHelper alloc] helper_ = [[CefJavaScriptDialogHelper alloc]
initHelperWithCallback:base::BindOnce( initHelperWithCallback:base::BindOnce(
&CefJavaScriptDialogRunnerMac::DialogClosed, &CefJavaScriptDialogRunnerMac::DialogClosed,
weak_ptr_factory_.GetWeakPtr())]); weak_ptr_factory_.GetWeakPtr())];
// Show the modal dialog. // Show the modal dialog.
NSAlert* alert = [helper_ alert]; NSAlert* alert = [helper_ alert];
NSTextField* field = nil; NSTextField* field = nil;
if (text_field) { if (text_field) {
field = [helper_ textField]; field = [helper_ textField];
[field setStringValue:base::SysUTF16ToNSString(default_prompt_text)]; field.stringValue = base::SysUTF16ToNSString(default_prompt_text);
} }
[alert setDelegate:helper_]; alert.delegate = helper_;
[alert setInformativeText:base::SysUTF16ToNSString(message_text)]; alert.informativeText = base::SysUTF16ToNSString(message_text);
std::u16string label; std::u16string label;
switch (message_type) { switch (message_type) {
@ -137,12 +143,12 @@ void CefJavaScriptDialogRunnerMac::Run(
label += u" - " + display_url; label += u" - " + display_url;
} }
[alert setMessageText:base::SysUTF16ToNSString(label)]; alert.messageText = base::SysUTF16ToNSString(label);
[alert addButtonWithTitle:@"OK"]; [alert addButtonWithTitle:@"OK"];
if (!one_button) { if (!one_button) {
NSButton* other = [alert addButtonWithTitle:@"Cancel"]; NSButton* other = [alert addButtonWithTitle:@"Cancel"];
[other setKeyEquivalent:@"\e"]; other.keyEquivalent = @"\e";
} }
// Calling beginSheetModalForWindow:nil is wrong API usage. For now work // Calling beginSheetModalForWindow:nil is wrong API usage. For now work
@ -168,21 +174,21 @@ void CefJavaScriptDialogRunnerMac::Run(
void CefJavaScriptDialogRunnerMac::Handle( void CefJavaScriptDialogRunnerMac::Handle(
bool accept, bool accept,
const std::u16string* prompt_override) { const std::u16string* prompt_override) {
if (helper_.get()) { if (helper_) {
DialogClosed(accept, prompt_override ? *prompt_override : std::u16string()); DialogClosed(accept, prompt_override ? *prompt_override : std::u16string());
} }
} }
void CefJavaScriptDialogRunnerMac::Cancel() { void CefJavaScriptDialogRunnerMac::Cancel() {
if (helper_.get()) { if (helper_) {
[helper_ cancel]; [helper_ cancel];
helper_.reset(nil); helper_ = nil;
} }
} }
void CefJavaScriptDialogRunnerMac::DialogClosed( void CefJavaScriptDialogRunnerMac::DialogClosed(
bool success, bool success,
const std::u16string& user_input) { const std::u16string& user_input) {
helper_.reset(nil); helper_ = nil;
std::move(callback_).Run(success, user_input); std::move(callback_).Run(success, user_input);
} }

View File

@ -8,8 +8,6 @@
#include "libcef/browser/menu_runner.h" #include "libcef/browser/menu_runner.h"
#include "base/mac/scoped_nsobject.h"
#if __OBJC__ #if __OBJC__
@class MenuControllerCocoa; @class MenuControllerCocoa;
#else #else
@ -28,7 +26,7 @@ class CefMenuRunnerMac : public CefMenuRunner {
void CancelContextMenu() override; void CancelContextMenu() override;
private: private:
base::scoped_nsobject<MenuControllerCocoa> menu_controller_; MenuControllerCocoa* __strong menu_controller_;
}; };
#endif // CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_MAC_H_ #endif // CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_MAC_H_

View File

@ -11,6 +11,10 @@
#import "ui/base/cocoa/menu_controller.h" #import "ui/base/cocoa/menu_controller.h"
#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
CefMenuRunnerMac::CefMenuRunnerMac() {} CefMenuRunnerMac::CefMenuRunnerMac() {}
CefMenuRunnerMac::~CefMenuRunnerMac() {} CefMenuRunnerMac::~CefMenuRunnerMac() {}
@ -20,17 +24,12 @@ bool CefMenuRunnerMac::RunContextMenu(
CefMenuModelImpl* model, CefMenuModelImpl* model,
const content::ContextMenuParams& params) { const content::ContextMenuParams& params) {
// Create a menu controller based on the model. // Create a menu controller based on the model.
menu_controller_.reset([[MenuControllerCocoa alloc] MenuControllerCocoa* menu_controller =
initWithModel:model->model() [[MenuControllerCocoa alloc] initWithModel:model->model()
delegate:nil delegate:nil
useWithPopUpButtonCell:NO]); useWithPopUpButtonCell:NO];
// Keep the menu controller alive (by adding an additional retain) until after menu_controller_ = menu_controller;
// the menu has been dismissed. Otherwise it will crash if the browser is
// destroyed (and consequently the menu controller is destroyed) while the
// menu is still pending.
base::scoped_nsobject<MenuControllerCocoa> menu_controller_ref(
menu_controller_);
// Make sure events can be pumped while the menu is up. // Make sure events can be pumped while the menu is up.
base::CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow; base::CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow;
@ -86,7 +85,7 @@ bool CefMenuRunnerMac::RunContextMenu(
} }
void CefMenuRunnerMac::CancelContextMenu() { void CefMenuRunnerMac::CancelContextMenu() {
if (menu_controller_.get()) { if (menu_controller_) {
[menu_controller_ cancel]; menu_controller_ = nil;
} }
} }

View File

@ -17,6 +17,10 @@
#import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h" #import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
#import "ui/views/cocoa/native_widget_mac_ns_window_host.h" #import "ui/views/cocoa/native_widget_mac_ns_window_host.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace { namespace {
AppShimHost* GetHostForBrowser(Browser* browser) { AppShimHost* GetHostForBrowser(Browser* browser) {
@ -133,9 +137,8 @@ void CefNativeWidgetMac::OnWindowInitialized() {
// From BrowserFrameMac::OnWindowInitialized. // From BrowserFrameMac::OnWindowInitialized.
if (auto* bridge = GetInProcessNSWindowBridge()) { if (auto* bridge = GetInProcessNSWindowBridge()) {
bridge->SetCommandDispatcher( bridge->SetCommandDispatcher([[ChromeCommandDispatcherDelegate alloc] init],
[[[ChromeCommandDispatcherDelegate alloc] init] autorelease], [[BrowserWindowCommandHandler alloc] init]);
[[[BrowserWindowCommandHandler alloc] init] autorelease]);
} else { } else {
if (auto* host = GetHostForBrowser(browser_view_->browser())) { if (auto* host = GetHostForBrowser(browser_view_->browser())) {
host->GetAppShim()->CreateCommandDispatcherForWidget( host->GetAppShim()->CreateCommandDispatcherForWidget(

View File

@ -49,6 +49,7 @@
#include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_switches.h"
#if BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_MAC)
#include "components/crash/core/common/objc_zombie.h"
#include "libcef/common/util_mac.h" #include "libcef/common/util_mac.h"
#elif BUILDFLAG(IS_POSIX) #elif BUILDFLAG(IS_POSIX)
#include "libcef/common/util_linux.h" #include "libcef/common/util_linux.h"
@ -94,7 +95,8 @@ absl::optional<int> AlloyMainDelegate::BasicStartupComplete() {
crash_reporting::BasicStartupComplete(command_line); crash_reporting::BasicStartupComplete(command_line);
#endif #endif
if (process_type.empty()) { const bool is_browser = process_type.empty();
if (is_browser) {
// In the browser process. Populate the global command-line object. // In the browser process. Populate the global command-line object.
if (settings_->command_line_args_disabled) { if (settings_->command_line_args_disabled) {
// Remove any existing command-line arguments. // Remove any existing command-line arguments.
@ -293,6 +295,12 @@ absl::optional<int> AlloyMainDelegate::BasicStartupComplete() {
std::ignore = commandLinePtr->Detach(nullptr); std::ignore = commandLinePtr->Detach(nullptr);
} }
#if BUILDFLAG(IS_MAC)
// Turns all deallocated Objective-C objects into zombies. Give the browser
// process a longer treadmill, since crashes there have more impact.
ObjcEvilDoers::ZombieEnable(true, is_browser ? 10000 : 1000);
#endif
// Initialize logging. // Initialize logging.
logging::LoggingSettings log_settings; logging::LoggingSettings log_settings;