summaryrefslogtreecommitdiffstats
path: root/content/renderer/renderer_main_platform_delegate_mac.mm
blob: 98b0aa4d84a35b6ba10776155d93340923f2707f (plain)
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