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

Side by Side Diff: content/browser/browser_io_surface_manager_mac.cc

Issue 1532813002: Replace IOSurfaceManager by directly passing IOSurface Mach ports over Chrome IPC. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 11 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
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/browser_io_surface_manager_mac.h"
6
7 #include <servers/bootstrap.h>
8
9 #include <string>
10
11 #include "base/logging.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/mach_logging.h"
14 #include "base/strings/stringprintf.h"
15 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
16
17 namespace content {
18 namespace {
19
20 // Returns the Mach port name to use when sending or receiving messages. |pid|
21 // is the process ID of the service.
22 std::string GetMachPortNameByPid(pid_t pid) {
23 return base::StringPrintf("%s.iosurfacemgr.%d", base::mac::BaseBundleID(),
24 pid);
25 }
26
27 // Amount of time to wait before giving up when sending a reply message.
28 const int kSendReplyTimeoutMs = 100;
29
30 } // namespace
31
32 // static
33 BrowserIOSurfaceManager* BrowserIOSurfaceManager::GetInstance() {
34 return base::Singleton<
35 BrowserIOSurfaceManager,
36 base::LeakySingletonTraits<BrowserIOSurfaceManager>>::get();
37 }
38
39 // static
40 base::mac::ScopedMachSendRight BrowserIOSurfaceManager::LookupServicePort(
41 pid_t pid) {
42 // Look up the named IOSurfaceManager port that's been registered with
43 // the bootstrap server.
44 mach_port_t port;
45 kern_return_t kr =
46 bootstrap_look_up(bootstrap_port,
47 GetMachPortNameByPid(pid).c_str(),
48 &port);
49 if (kr != KERN_SUCCESS) {
50 BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up";
51 return base::mac::ScopedMachSendRight();
52 }
53
54 return base::mac::ScopedMachSendRight(port);
55 }
56
57 // static
58 std::string BrowserIOSurfaceManager::GetMachPortName() {
59 return GetMachPortNameByPid(getpid());
60 }
61
62 bool BrowserIOSurfaceManager::RegisterIOSurface(gfx::IOSurfaceId io_surface_id,
63 int client_id,
64 IOSurfaceRef io_surface) {
65 base::AutoLock lock(lock_);
66
67 IOSurfaceMapKey key(io_surface_id, client_id);
68 DCHECK(io_surfaces_.find(key) == io_surfaces_.end());
69 io_surfaces_.insert(
70 std::make_pair(key, base::ScopedCFTypeRef<IOSurfaceRef>(io_surface)));
71 return true;
72 }
73
74 void BrowserIOSurfaceManager::UnregisterIOSurface(
75 gfx::IOSurfaceId io_surface_id,
76 int client_id) {
77 base::AutoLock lock(lock_);
78
79 IOSurfaceMapKey key(io_surface_id, client_id);
80 DCHECK(io_surfaces_.find(key) != io_surfaces_.end());
81 io_surfaces_.erase(key);
82 }
83
84 IOSurfaceRef BrowserIOSurfaceManager::AcquireIOSurface(
85 gfx::IOSurfaceId io_surface_id) {
86 base::AutoLock lock(lock_);
87
88 IOSurfaceMapKey key(
89 io_surface_id,
90 BrowserGpuChannelHostFactory::instance()->GetGpuChannelId());
91 auto it = io_surfaces_.find(key);
92 if (it == io_surfaces_.end()) {
93 LOG(ERROR) << "Invalid Id for IOSurface " << io_surface_id.id;
94 return nullptr;
95 }
96
97 IOSurfaceRef io_surface = it->second;
98 CFRetain(io_surface);
99 return io_surface;
100 }
101
102 void BrowserIOSurfaceManager::EnsureRunning() {
103 base::AutoLock lock(lock_);
104
105 if (initialized_)
106 return;
107
108 // Do not attempt to reinitialize in the event of failure.
109 initialized_ = true;
110
111 if (!Initialize()) {
112 LOG(ERROR) << "Failed to initialize the BrowserIOSurfaceManager";
113 }
114 }
115
116 IOSurfaceManagerToken BrowserIOSurfaceManager::GenerateGpuProcessToken() {
117 base::AutoLock lock(lock_);
118
119 DCHECK(gpu_process_token_.IsZero());
120 gpu_process_token_ = IOSurfaceManagerToken::Generate();
121 DCHECK(gpu_process_token_.Verify());
122 return gpu_process_token_;
123 }
124
125 void BrowserIOSurfaceManager::InvalidateGpuProcessToken() {
126 base::AutoLock lock(lock_);
127
128 DCHECK(!gpu_process_token_.IsZero());
129 gpu_process_token_.SetZero();
130 io_surfaces_.clear();
131 }
132
133 IOSurfaceManagerToken BrowserIOSurfaceManager::GenerateChildProcessToken(
134 int child_process_id) {
135 base::AutoLock lock(lock_);
136
137 IOSurfaceManagerToken token = IOSurfaceManagerToken::Generate();
138 DCHECK(token.Verify());
139 child_process_ids_[token] = child_process_id;
140 return token;
141 }
142
143 void BrowserIOSurfaceManager::InvalidateChildProcessToken(
144 const IOSurfaceManagerToken& token) {
145 base::AutoLock lock(lock_);
146
147 DCHECK(child_process_ids_.find(token) != child_process_ids_.end());
148 child_process_ids_.erase(token);
149 }
150
151 BrowserIOSurfaceManager::BrowserIOSurfaceManager() : initialized_(false) {
152 }
153
154 BrowserIOSurfaceManager::~BrowserIOSurfaceManager() {
155 }
156
157 bool BrowserIOSurfaceManager::Initialize() {
158 lock_.AssertAcquired();
159 DCHECK(!server_port_.is_valid());
160
161 // Check in with launchd and publish the service name.
162 mach_port_t port;
163 kern_return_t kr = bootstrap_check_in(
164 bootstrap_port, GetMachPortName().c_str(), &port);
165 if (kr != KERN_SUCCESS) {
166 BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_check_in";
167 return false;
168 }
169 server_port_.reset(port);
170
171 // Start the dispatch source.
172 std::string queue_name =
173 base::StringPrintf("%s.IOSurfaceManager", base::mac::BaseBundleID());
174 dispatch_source_.reset(
175 new base::DispatchSourceMach(queue_name.c_str(), server_port_.get(), ^{
176 HandleRequest();
177 }));
178 dispatch_source_->Resume();
179
180 return true;
181 }
182
183 void BrowserIOSurfaceManager::HandleRequest() {
184 struct {
185 union {
186 mach_msg_header_t header;
187 IOSurfaceManagerHostMsg_RegisterIOSurface register_io_surface;
188 IOSurfaceManagerHostMsg_UnregisterIOSurface unregister_io_surface;
189 IOSurfaceManagerHostMsg_AcquireIOSurface acquire_io_surface;
190 } msg;
191 mach_msg_trailer_t trailer;
192 } request = {{{0}}};
193 request.msg.header.msgh_size = sizeof(request);
194 request.msg.header.msgh_local_port = server_port_.get();
195
196 kern_return_t kr =
197 mach_msg(&request.msg.header, MACH_RCV_MSG, 0, sizeof(request),
198 server_port_.get(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
199 if (kr != KERN_SUCCESS) {
200 MACH_LOG(ERROR, kr) << "mach_msg";
201 return;
202 }
203
204 union {
205 mach_msg_header_t header;
206 IOSurfaceManagerMsg_RegisterIOSurfaceReply register_io_surface;
207 IOSurfaceManagerMsg_AcquireIOSurfaceReply acquire_io_surface;
208 } reply = {{0}};
209
210 switch (request.msg.header.msgh_id) {
211 case IOSurfaceManagerHostMsg_RegisterIOSurface::ID:
212 HandleRegisterIOSurfaceRequest(request.msg.register_io_surface,
213 &reply.register_io_surface);
214 break;
215 case IOSurfaceManagerHostMsg_UnregisterIOSurface::ID:
216 HandleUnregisterIOSurfaceRequest(request.msg.unregister_io_surface);
217 // Unregister requests are asynchronous and do not require a reply as
218 // there is no guarantee for how quickly an IO surface is removed from
219 // the IOSurfaceManager instance after it has been deleted by a child
220 // process.
221 return;
222 case IOSurfaceManagerHostMsg_AcquireIOSurface::ID:
223 HandleAcquireIOSurfaceRequest(request.msg.acquire_io_surface,
224 &reply.acquire_io_surface);
225 break;
226 default:
227 LOG(ERROR) << "Unknown message received!";
228 return;
229 }
230
231 kr = mach_msg(&reply.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
232 reply.header.msgh_size, 0, MACH_PORT_NULL, kSendReplyTimeoutMs,
233 MACH_PORT_NULL);
234 if (kr != KERN_SUCCESS) {
235 MACH_LOG(ERROR, kr) << "mach_msg";
236 }
237 }
238
239 void BrowserIOSurfaceManager::HandleRegisterIOSurfaceRequest(
240 const IOSurfaceManagerHostMsg_RegisterIOSurface& request,
241 IOSurfaceManagerMsg_RegisterIOSurfaceReply* reply) {
242 base::AutoLock lock(lock_);
243
244 reply->header.msgh_bits = MACH_MSGH_BITS_REMOTE(request.header.msgh_bits);
245 reply->header.msgh_remote_port = request.header.msgh_remote_port;
246 reply->header.msgh_size = sizeof(*reply);
247 reply->body.msgh_descriptor_count = 0;
248 reply->result = false;
249
250 IOSurfaceManagerToken token;
251 static_assert(sizeof(request.token_name) == sizeof(token.name),
252 "Mach message token size doesn't match expectation.");
253 token.SetName(request.token_name);
254 if (token.IsZero() || token != gpu_process_token_) {
255 LOG(ERROR) << "Illegal message from non-GPU process!";
256 return;
257 }
258
259 base::mac::ScopedMachSendRight io_surface_port(request.io_surface_port.name);
260 base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
261 IOSurfaceLookupFromMachPort(io_surface_port.get()));
262 if (!io_surface) {
263 LOG(ERROR) << "Failed to open registered IOSurface port!";
264 return;
265 }
266 IOSurfaceMapKey key(gfx::IOSurfaceId(request.io_surface_id),
267 request.client_id);
268 io_surfaces_.insert(std::make_pair(key, io_surface));
269 reply->result = true;
270 }
271
272 bool BrowserIOSurfaceManager::HandleUnregisterIOSurfaceRequest(
273 const IOSurfaceManagerHostMsg_UnregisterIOSurface& request) {
274 base::AutoLock lock(lock_);
275
276 IOSurfaceManagerToken token;
277 static_assert(sizeof(request.token_name) == sizeof(token.name),
278 "Mach message token size doesn't match expectation.");
279 token.SetName(request.token_name);
280 if (token.IsZero() || token != gpu_process_token_) {
281 LOG(ERROR) << "Illegal message from non-GPU process!";
282 return false;
283 }
284
285 IOSurfaceMapKey key(gfx::IOSurfaceId(request.io_surface_id),
286 request.client_id);
287 io_surfaces_.erase(key);
288 return true;
289 }
290
291 void BrowserIOSurfaceManager::HandleAcquireIOSurfaceRequest(
292 const IOSurfaceManagerHostMsg_AcquireIOSurface& request,
293 IOSurfaceManagerMsg_AcquireIOSurfaceReply* reply) {
294 base::AutoLock lock(lock_);
295
296 reply->header.msgh_bits =
297 MACH_MSGH_BITS_REMOTE(request.header.msgh_bits) | MACH_MSGH_BITS_COMPLEX;
298 reply->header.msgh_remote_port = request.header.msgh_remote_port;
299 reply->header.msgh_size = sizeof(*reply);
300 reply->body.msgh_descriptor_count = 0;
301 reply->result = false;
302 reply->io_surface_port.name = MACH_PORT_NULL;
303 reply->io_surface_port.disposition = 0;
304 reply->io_surface_port.type = 0;
305
306 IOSurfaceManagerToken token;
307 static_assert(sizeof(request.token_name) == sizeof(token.name),
308 "Mach message token size doesn't match expectation.");
309 token.SetName(request.token_name);
310 auto child_process_id_it = child_process_ids_.find(token);
311 if (child_process_id_it == child_process_ids_.end()) {
312 LOG(ERROR) << "Illegal message from non-child process!";
313 return;
314 }
315
316 reply->result = true;
317 IOSurfaceMapKey key(gfx::IOSurfaceId(request.io_surface_id),
318 child_process_id_it->second);
319 auto it = io_surfaces_.find(key);
320 if (it == io_surfaces_.end()) {
321 LOG(ERROR) << "Invalid Id for IOSurface " << request.io_surface_id;
322 return;
323 }
324
325 reply->body.msgh_descriptor_count = 1;
326 reply->io_surface_port.name = IOSurfaceCreateMachPort(it->second);
327 reply->io_surface_port.disposition = MACH_MSG_TYPE_MOVE_SEND;
328 reply->io_surface_port.type = MACH_MSG_PORT_DESCRIPTOR;
329 }
330
331 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/browser_io_surface_manager_mac.h ('k') | content/browser/browser_io_surface_manager_mac_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698