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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
// 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"
#import "base/mac/foundation_util.h"
#import "base/mac/crash_logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#include "content/common/sandbox_mac.h"
#include "content/public/common/content_switches.h"
#import "content/public/common/injection_test_mac.h"
#include "content/common/sandbox_init_mac.h"
#include "third_party/mach_override/mach_override.h"
extern "C" {
// SPI logging functions for CF that are exported externally.
void CFLog(int32_t level, CFStringRef format, ...);
void _CFLogvEx(void* log_func, void* copy_desc_func,
CFDictionaryRef format_options, int32_t level,
CFStringRef format, va_list args);
} // extern "C"
namespace content {
namespace {
// This leaked array stores the text input services input and layout sources,
// which is returned in CrTISCreateInputSourceList(). This list is computed
// right after the sandbox is initialized.
CFArrayRef g_text_input_services_source_list_ = NULL;
CFArrayRef CrTISCreateInputSourceList(
CFDictionaryRef properties,
Boolean includeAllInstalled) {
DCHECK(g_text_input_services_source_list_);
// Callers assume ownership of the result, so increase the retain count.
CFRetain(g_text_input_services_source_list_);
return g_text_input_services_source_list_;
}
// Text Input Services expects to be able to XPC to HIServices, but the
// renderer sandbox blocks that. TIS then becomes very vocal about this on
// every new renderer startup, so filter out those log messages.
void CrRendererCFLog(int32_t level, CFStringRef format, ...) {
const CFStringRef kAnnoyingLogMessages[] = {
CFSTR("Error received in message reply handler: %s\n"),
CFSTR("Connection Invalid error for service %s.\n"),
};
for (size_t i = 0; i < arraysize(kAnnoyingLogMessages); ++i) {
if (CFStringCompare(format, kAnnoyingLogMessages[i], 0) ==
kCFCompareEqualTo) {
return;
}
}
va_list args;
va_start(args, format);
_CFLogvEx(NULL, NULL, NULL, level, format, args);
va_end(args);
}
} // 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() {
// Initialize NSApplication up front. Without this call, drawing of
// native UI elements (e.g. buttons) in WebKit will explode.
[NSApplication sharedApplication];
if (![NSThread isMultiThreaded]) {
NSString* string = @"";
[NSThread detachNewThreadSelector:@selector(length)
toTarget:string
withObject:nil];
}
}
void RendererMainPlatformDelegate::PlatformUninitialize() {
}
static void LogTestMessage(std::string message, bool is_error) {
if (is_error)
LOG(ERROR) << message;
else
LOG(INFO) << message;
}
bool RendererMainPlatformDelegate::InitSandboxTests(bool no_sandbox) {
const CommandLine& command_line = parameters_.command_line;
if (command_line.HasSwitch(switches::kTestSandbox)) {
std::string bundle_path =
command_line.GetSwitchValueNative(switches::kTestSandbox);
if (bundle_path.empty()) {
NOTREACHED() << "Bad bundle path";
return false;
}
NSBundle* tests_bundle =
[NSBundle bundleWithPath:base::SysUTF8ToNSString(bundle_path)];
if (![tests_bundle load]) {
NOTREACHED() << "Failed to load bundle";
return false;
}
sandbox_tests_bundle_ = [tests_bundle retain];
[objc_getClass("RendererSandboxTestsRunner") setLogFunction:LogTestMessage];
}
return true;
}
bool RendererMainPlatformDelegate::EnableSandbox() {
// See http://crbug.com/31225 and http://crbug.com/152566
// TODO: Don't do this on newer OS X revisions that have a fix for
// http://openradar.appspot.com/radar?id=1156410
// To check if this is broken:
// 1. Enable Multi language input (simplified chinese)
// 2. Ensure "Show/Hide Trackpad Handwriting" shortcut works.
// (ctrl+shift+space).
// 3. Now open a new tab in Google Chrome or start Google Chrome
// 4. Try ctrl+shift+space shortcut again. Shortcut will not work, IME will
// either not appear or (worse) not disappear on ctrl-shift-space.
// (Run `ps aux | grep Chinese` (10.6/10.7) or `ps aux | grep Trackpad`
// and then kill that pid to make it go away.)
//
// Chinese Handwriting was introduced in 10.6 and is confirmed broken on
// 10.6, 10.7, and 10.8.
mach_error_t err = mach_override_ptr(
(void*)&TISCreateInputSourceList,
(void*)&CrTISCreateInputSourceList,
NULL);
CHECK_EQ(err_none, err);
// Override the private CFLog function so that the console is not spammed
// by TIS failing to connect to HIServices over XPC.
err = mach_override_ptr((void*)&CFLog, (void*)&CrRendererCFLog, NULL);
CHECK_EQ(err_none, err);
// Enable the sandbox.
bool sandbox_initialized = InitializeSandbox();
// After the sandbox is initialized, call into TIS. Doing this before
// the sandbox is in place will open up renderer access to the
// pasteboard and an XPC connection to "com.apple.hiservices-xpcservice".
base::mac::ScopedCFTypeRef<TISInputSourceRef> layout_source(
TISCopyCurrentKeyboardLayoutInputSource());
base::mac::ScopedCFTypeRef<TISInputSourceRef> input_source(
TISCopyCurrentKeyboardInputSource());
CFTypeRef source_list[] = { layout_source.get(), input_source.get() };
g_text_input_services_source_list_ = CFArrayCreate(kCFAllocatorDefault,
source_list, arraysize(source_list), &kCFTypeArrayCallBacks);
return sandbox_initialized;
}
void RendererMainPlatformDelegate::RunSandboxTests(bool no_sandbox) {
Class tests_runner = objc_getClass("RendererSandboxTestsRunner");
if (tests_runner) {
if (![tests_runner runTests])
LOG(ERROR) << "Running renderer with failing sandbox tests!";
[sandbox_tests_bundle_ unload];
[sandbox_tests_bundle_ release];
sandbox_tests_bundle_ = nil;
}
}
} // namespace content
|