1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/renderer_main_platform_delegate.h"
#include <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>
#include <objc/runtime.h>
#include "base/command_line.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "content/common/sandbox_mac.h"
#include "content/public/common/content_switches.h"
#include "content/common/sandbox_init_mac.h"
namespace content {
namespace {
// You are about to read a pretty disgusting hack. In a static initializer,
// CoreFoundation decides to connect with cfprefsd(8) using Mach IPC. There is
// no public way to close this Mach port after-the-fact, nor a way to stop it
// from happening since it is done pre-main in dyld. But the address of the
// CFMachPort can be found in the run loop's string description. Below, that
// address is parsed, cast, and then used to invalidate the Mach port to
// disable communication with cfprefsd.
void DisconnectCFNotificationCenter() {
base::ScopedCFTypeRef<CFStringRef> run_loop_description(
CFCopyDescription(CFRunLoopGetCurrent()));
const CFIndex length = CFStringGetLength(run_loop_description);
for (CFIndex i = 0; i < length; ) {
// Find the start of a CFMachPort run loop source, which looks like this,
// without new lines:
// 1 : <CFRunLoopSource 0x7d16ea90 [0xa160af80]>{signalled = No,
// valid = Yes, order = 0, context =
// <CFMachPort 0x7d16fe00 [0xa160af80]>{valid = Yes, port = 3a0f,
// source = 0x7d16ea90, callout =
// _ZL14MessageHandlerP12__CFMachPortPvlS1_ (0x96df59c2), context =
// <CFMachPort context 0x1475b>}}
CFRange run_loop_source_context_range;
if (!CFStringFindWithOptions(run_loop_description,
CFSTR(", context = <CFMachPort "), CFRangeMake(i, length - i),
0, &run_loop_source_context_range)) {
break;
}
i = run_loop_source_context_range.location +
run_loop_source_context_range.length;
// The address of the CFMachPort is the first hexadecimal address after the
// CF type name.
CFRange port_address_range = CFRangeMake(i, 0);
for (CFIndex j = port_address_range.location; j < length; ++j) {
UniChar c = CFStringGetCharacterAtIndex(run_loop_description, j);
if (c == ' ')
break;
++port_address_range.length;
}
base::ScopedCFTypeRef<CFStringRef> port_address_string(
CFStringCreateWithSubstring(NULL, run_loop_description,
port_address_range));
if (!port_address_string)
continue;
// Convert the string to an address.
std::string port_address_std_string =
base::SysCFStringRefToUTF8(port_address_string);
#if __LP64__
uint64 port_address = 0;
if (!base::HexStringToUInt64(port_address_std_string, &port_address))
continue;
#else
uint32 port_address = 0;
if (!base::HexStringToUInt(port_address_std_string, &port_address))
continue;
#endif
// Cast the address to an object.
CFMachPortRef mach_port = reinterpret_cast<CFMachPortRef>(port_address);
if (CFGetTypeID(mach_port) != CFMachPortGetTypeID())
continue;
// Verify that this is the Mach port that needs to be disconnected by the
// name of its callout function. Example description (no new lines):
// <CFMachPort 0x7d16fe00 [0xa160af80]>{valid = Yes, port = 3a0f, source =
// 0x7d16ea90, callout = __CFXNotificationReceiveFromServer (0x96df59c2),
// context = <CFMachPort context 0x1475b>}
base::ScopedCFTypeRef<CFStringRef> port_description(
CFCopyDescription(mach_port));
if (CFStringFindWithOptions(port_description,
CFSTR(", callout = __CFXNotificationReceiveFromServer ("),
CFRangeMake(0, CFStringGetLength(port_description)),
0,
NULL)) {
CFMachPortInvalidate(mach_port);
return;
}
}
}
} // namespace
RendererMainPlatformDelegate::RendererMainPlatformDelegate(
const MainFunctionParams& parameters)
: parameters_(parameters) {
}
RendererMainPlatformDelegate::~RendererMainPlatformDelegate() {
}
// TODO(mac-port): Any code needed to initialize a process for purposes of
// running a renderer needs to also be reflected in chrome_main.cc for
// --single-process support.
void RendererMainPlatformDelegate::PlatformInitialize() {
if (base::mac::IsOSYosemiteOrLater()) {
// This is needed by the NSAnimations run for the scrollbars. If we switch
// from native scrollers to drawing them in some other way, this warmup can
// be removed <http://crbug.com/306348>.
[NSScreen screens];
}
if (![NSThread isMultiThreaded]) {
NSString* string = @"";
[NSThread detachNewThreadSelector:@selector(length)
toTarget:string
withObject:nil];
}
}
void RendererMainPlatformDelegate::PlatformUninitialize() {
}
bool RendererMainPlatformDelegate::EnableSandbox() {
// Enable the sandbox.
bool sandbox_initialized = InitializeSandbox();
// The sandbox is now engaged. Make sure that the renderer has not connected
// itself to Cocoa.
CHECK(NSApp == nil);
DisconnectCFNotificationCenter();
return sandbox_initialized;
}
} // namespace content
|