OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/mach_broker_mac.h" | 5 #include "content/browser/mach_broker_mac.h" |
6 | 6 |
7 #include <bsm/libbsm.h> | 7 #include <bsm/libbsm.h> |
8 #include <servers/bootstrap.h> | 8 #include <servers/bootstrap.h> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/lazy_instance.h" | |
13 #include "base/logging.h" | 14 #include "base/logging.h" |
14 #include "base/mac/foundation_util.h" | 15 #include "base/mac/foundation_util.h" |
15 #include "base/mac/mach_logging.h" | 16 #include "base/mac/mach_logging.h" |
16 #include "base/mac/scoped_mach_port.h" | 17 #include "base/mac/scoped_mach_port.h" |
17 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
18 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
19 #include "base/strings/sys_string_conversions.h" | 20 #include "base/strings/sys_string_conversions.h" |
20 #include "base/threading/platform_thread.h" | 21 #include "base/threading/platform_thread.h" |
21 #include "content/browser/renderer_host/render_process_host_impl.h" | 22 #include "content/browser/renderer_host/render_process_host_impl.h" |
22 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
23 #include "content/public/browser/child_process_data.h" | 24 #include "content/public/browser/child_process_data.h" |
24 #include "content/public/browser/notification_service.h" | 25 #include "content/public/browser/notification_service.h" |
25 #include "content/public/browser/notification_types.h" | 26 #include "content/public/browser/notification_types.h" |
26 #include "content/public/common/content_switches.h" | 27 #include "content/public/common/content_switches.h" |
27 | 28 |
28 namespace content { | 29 namespace content { |
29 | 30 |
30 namespace { | 31 namespace { |
31 | 32 |
33 const mach_msg_id_t kMachBroker_ChildId = 1; | |
Daniele Castagna
2015/05/08 18:58:30
What about moving the ids inside the structs they
reveman
2015/05/09 15:54:54
Added MACH_MESSAGE_ID macro to latest patch that u
| |
34 | |
32 // Mach message structure used in the child as a sending message. | 35 // Mach message structure used in the child as a sending message. |
33 struct MachBroker_ChildSendMsg { | 36 struct MachBroker_ChildMsg { |
34 mach_msg_header_t header; | 37 mach_msg_header_t header; |
35 mach_msg_body_t body; | 38 mach_msg_body_t body; |
36 mach_msg_port_descriptor_t child_task_port; | 39 mach_msg_port_descriptor_t child_task_port; |
37 }; | 40 }; |
38 | 41 |
39 // Complement to the ChildSendMsg, this is used in the parent for receiving | 42 // Complement to the ChildMsg, this is used in the parent for receiving |
40 // a message. Contains a message trailer with audit information. | 43 // a message. Contains a message trailer with audit information. |
41 struct MachBroker_ParentRecvMsg : public MachBroker_ChildSendMsg { | 44 struct MachBroker_ChildRecvMsg : public MachBroker_ChildMsg { |
42 mach_msg_audit_trailer_t trailer; | 45 mach_msg_audit_trailer_t trailer; |
43 }; | 46 }; |
44 | 47 |
48 const mach_msg_id_t kMachBroker_RegisterIOSurfaceId = 2; | |
49 | |
50 // Mach message structure used in the child as a sending message. | |
51 struct MachBroker_RegisterIOSurfaceMsg { | |
52 mach_msg_header_t header; | |
53 mach_msg_body_t body; | |
54 mach_msg_port_descriptor_t io_surface_port; | |
55 int io_surface_id; | |
56 int client_id; | |
57 }; | |
58 | |
59 // Complement to the RegisterIOSurfaceMsg, this is used in the parent for | |
60 // receiving a message. Contains a message trailer with audit information. | |
61 struct MachBroker_RegisterIOSurfaceRecvMsg | |
62 : public MachBroker_RegisterIOSurfaceMsg { | |
63 mach_msg_audit_trailer_t trailer; | |
64 }; | |
65 | |
66 // Mach message structure used in the parent as a sending message. | |
67 struct MachBroker_RegisterIOSurfaceReplyMsg { | |
68 mach_msg_header_t header; | |
69 mach_msg_body_t body; | |
70 boolean_t result; | |
71 }; | |
72 | |
73 // Complement to the RegisterIOSurfaceReplyMsg, this is used in the child | |
74 // for receiving a message. Contains a message trailer. | |
75 struct MachBroker_RegisterIOSurfaceReplyRecvMsg | |
76 : public MachBroker_RegisterIOSurfaceReplyMsg { | |
77 mach_msg_trailer_t trailer; | |
78 }; | |
79 | |
80 const mach_msg_id_t kMachBroker_UnregisterIOSurfaceId = 3; | |
81 | |
82 // Mach message structure used in the child as a sending message. | |
83 struct MachBroker_UnregisterIOSurfaceMsg { | |
84 mach_msg_header_t header; | |
85 mach_msg_body_t body; | |
86 int io_surface_id; | |
87 int client_id; | |
88 }; | |
89 | |
90 // Complement to the UnregisterIOSurfaceMsg, this is used in the parent for | |
91 // receiving a message. Contains a message trailer with audit information. | |
92 struct MachBroker_UnregisterIOSurfaceRecvMsg | |
93 : public MachBroker_UnregisterIOSurfaceMsg { | |
94 mach_msg_audit_trailer_t trailer; | |
95 }; | |
96 | |
97 const mach_msg_id_t kMachBroker_AcquireIOSurfaceId = 4; | |
98 | |
99 // Mach message structure used in the child as a sending message. | |
100 struct MachBroker_AcquireIOSurfaceMsg { | |
101 mach_msg_header_t header; | |
102 mach_msg_body_t body; | |
103 int io_surface_id; | |
104 }; | |
105 | |
106 // Complement to the AcquireIOSurfaceMsg, this is used in the parent for | |
107 // receiving a message. Contains a message trailer with audit information. | |
108 struct MachBroker_AcquireIOSurfaceRecvMsg | |
109 : public MachBroker_AcquireIOSurfaceMsg { | |
110 mach_msg_audit_trailer_t trailer; | |
111 }; | |
112 | |
113 // Mach message structure used in the parent as a sending message. | |
114 struct MachBroker_AcquireIOSurfaceReplyMsg { | |
115 mach_msg_header_t header; | |
116 mach_msg_body_t body; | |
117 mach_msg_port_descriptor_t io_surface_port; | |
118 }; | |
119 | |
120 // Complement to the AcquireIOSurfaceReplyMsg, this is used in the child for | |
121 // receiving a message. Contains a message trailer. | |
122 struct MachBroker_AcquireIOSurfaceReplyRecvMsg | |
123 : public MachBroker_AcquireIOSurfaceReplyMsg { | |
124 mach_msg_trailer_t trailer; | |
125 }; | |
126 | |
127 // Returns the Mach port name to use when sending or receiving messages. | |
128 // Does the Right Thing in the browser and in child processes. | |
129 std::string GetMachPortName() { | |
130 const base::CommandLine* command_line = | |
131 base::CommandLine::ForCurrentProcess(); | |
132 const bool is_child = command_line->HasSwitch(switches::kProcessType); | |
133 | |
134 // In non-browser (child) processes, use the parent's pid. | |
135 const pid_t pid = is_child ? getppid() : getpid(); | |
136 return base::StringPrintf("%s.rohitfork.%d", base::mac::BaseBundleID(), pid); | |
137 } | |
138 | |
139 struct ChildSendPortLazyInstanceTraits | |
140 : public base::internal::LeakyLazyInstanceTraits< | |
141 base::mac::ScopedMachSendRight> { | |
142 static base::mac::ScopedMachSendRight* New(void* instance) { | |
143 mach_port_t send_port = MACH_PORT_NULL; | |
144 // Look up the named MachBroker port that's been registered with the | |
145 // bootstrap server. | |
146 kern_return_t kr = bootstrap_look_up( | |
147 bootstrap_port, const_cast<char*>(GetMachPortName().c_str()), | |
148 &send_port); | |
149 if (kr != KERN_SUCCESS) | |
150 BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up"; | |
151 | |
152 // Use placement new to initialize our instance in our preallocated space. | |
153 return new (instance) base::mac::ScopedMachSendRight(send_port); | |
154 } | |
155 }; | |
156 | |
157 base::LazyInstance<base::mac::ScopedMachSendRight, | |
158 ChildSendPortLazyInstanceTraits> g_child_send_port = | |
159 LAZY_INSTANCE_INITIALIZER; | |
160 | |
161 struct ChildReceivePortLazyInstanceTraits | |
162 : public base::internal::LeakyLazyInstanceTraits< | |
163 base::mac::ScopedMachSendRight> { | |
164 static base::mac::ScopedMachSendRight* New(void* instance) { | |
165 mach_port_t receive_port = MACH_PORT_NULL; | |
166 kern_return_t kr = mach_port_allocate( | |
167 mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &receive_port); | |
168 if (kr != KERN_SUCCESS) | |
169 MACH_LOG(ERROR, kr) << "mach_port_allocate"; | |
170 | |
171 // Use placement new to initialize our instance in our preallocated space. | |
172 return new (instance) base::mac::ScopedMachSendRight(receive_port); | |
173 } | |
174 }; | |
175 | |
176 base::LazyInstance<base::mac::ScopedMachSendRight, | |
177 ChildReceivePortLazyInstanceTraits> g_child_receive_port = | |
178 LAZY_INSTANCE_INITIALIZER; | |
179 | |
180 base::LazyInstance<base::Lock> g_child_lock = LAZY_INSTANCE_INITIALIZER; | |
181 | |
45 } // namespace | 182 } // namespace |
46 | 183 |
47 class MachListenerThreadDelegate : public base::PlatformThread::Delegate { | 184 class MachListenerThreadDelegate : public base::PlatformThread::Delegate { |
48 public: | 185 public: |
49 explicit MachListenerThreadDelegate(MachBroker* broker) | 186 explicit MachListenerThreadDelegate(MachBroker* broker) |
50 : broker_(broker), | 187 : broker_(broker), |
51 server_port_(MACH_PORT_NULL) { | 188 server_port_(MACH_PORT_NULL) { |
52 DCHECK(broker_); | 189 DCHECK(broker_); |
53 } | 190 } |
54 | 191 |
(...skipping 17 matching lines...) Expand all Loading... | |
72 MACH_LOG(ERROR, kr) << "mach_port_insert_right"; | 209 MACH_LOG(ERROR, kr) << "mach_port_insert_right"; |
73 return false; | 210 return false; |
74 } | 211 } |
75 // Deallocate the right after registering with the bootstrap server. | 212 // Deallocate the right after registering with the bootstrap server. |
76 base::mac::ScopedMachSendRight send_right(port); | 213 base::mac::ScopedMachSendRight send_right(port); |
77 | 214 |
78 // Register the port with the bootstrap server. Because bootstrap_register | 215 // Register the port with the bootstrap server. Because bootstrap_register |
79 // is deprecated, this has to be wraped in an ObjC interface. | 216 // is deprecated, this has to be wraped in an ObjC interface. |
80 NSPort* ns_port = [NSMachPort portWithMachPort:port | 217 NSPort* ns_port = [NSMachPort portWithMachPort:port |
81 options:NSMachPortDeallocateNone]; | 218 options:NSMachPortDeallocateNone]; |
82 NSString* name = base::SysUTF8ToNSString(broker_->GetMachPortName()); | 219 NSString* name = base::SysUTF8ToNSString(GetMachPortName()); |
83 return [[NSMachBootstrapServer sharedInstance] registerPort:ns_port | 220 return [[NSMachBootstrapServer sharedInstance] registerPort:ns_port |
84 name:name]; | 221 name:name]; |
85 } | 222 } |
86 | 223 |
87 // Implement |PlatformThread::Delegate|. | 224 // Implement |PlatformThread::Delegate|. |
88 void ThreadMain() override { | 225 void ThreadMain() override { |
89 MachBroker_ParentRecvMsg msg; | 226 union { |
227 mach_msg_header_t header; | |
228 MachBroker_ChildRecvMsg child; | |
229 MachBroker_RegisterIOSurfaceRecvMsg register_io_surface; | |
230 MachBroker_UnregisterIOSurfaceRecvMsg unregister_io_surface; | |
231 MachBroker_AcquireIOSurfaceRecvMsg acquire_io_surface; | |
232 } msg; | |
90 bzero(&msg, sizeof(msg)); | 233 bzero(&msg, sizeof(msg)); |
91 msg.header.msgh_size = sizeof(msg); | 234 msg.header.msgh_size = sizeof(msg); |
92 msg.header.msgh_local_port = server_port_.get(); | 235 msg.header.msgh_local_port = server_port_.get(); |
93 | 236 |
94 const mach_msg_option_t options = MACH_RCV_MSG | | 237 const mach_msg_option_t options = MACH_RCV_MSG | |
95 MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) | | 238 MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) | |
96 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT); | 239 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT); |
97 | 240 |
98 kern_return_t kr; | 241 kern_return_t kr; |
99 while ((kr = mach_msg(&msg.header, | 242 while ((kr = mach_msg(&msg.header, |
100 options, | 243 options, |
101 0, | 244 0, |
102 sizeof(msg), | 245 sizeof(msg), |
103 server_port_, | 246 server_port_, |
104 MACH_MSG_TIMEOUT_NONE, | 247 MACH_MSG_TIMEOUT_NONE, |
105 MACH_PORT_NULL)) == KERN_SUCCESS) { | 248 MACH_PORT_NULL)) == KERN_SUCCESS) { |
106 // Use the kernel audit information to make sure this message is from | 249 // Use the kernel audit information to make sure this message is from |
107 // a task that this process spawned. The kernel audit token contains the | 250 // a task that this process spawned. The kernel audit token contains |
108 // unspoofable pid of the task that sent the message. | 251 // the unspoofable pid of the task that sent the message. |
109 // | 252 mach_msg_audit_trailer_t* trailer = |
253 reinterpret_cast<mach_msg_audit_trailer_t*>( | |
254 reinterpret_cast<vm_address_t>(&msg.header) + | |
255 round_msg(msg.header.msgh_size)); | |
110 // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid(). | 256 // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid(). |
111 pid_t child_pid; | 257 pid_t child_pid; |
112 audit_token_to_au32(msg.trailer.msgh_audit, | 258 audit_token_to_au32(trailer->msgh_audit, NULL, NULL, NULL, NULL, NULL, |
113 NULL, NULL, NULL, NULL, NULL, &child_pid, NULL, NULL); | 259 &child_pid, NULL, NULL); |
114 | 260 |
115 mach_port_t child_task_port = msg.child_task_port.name; | 261 // Take the lock. |
262 base::AutoLock lock(broker_->GetLock()); | |
116 | 263 |
117 // Take the lock and update the broker information. | 264 switch (msg.header.msgh_id) { |
118 base::AutoLock lock(broker_->GetLock()); | 265 case kMachBroker_ChildId: { |
119 broker_->FinalizePid(child_pid, child_task_port); | 266 mach_port_t child_task_port = msg.child.child_task_port.name; |
267 | |
268 // Update the broker information. | |
269 broker_->FinalizePid(child_pid, child_task_port); | |
270 } break; | |
271 case kMachBroker_RegisterIOSurfaceId: { | |
272 mach_port_t io_surface_port = | |
273 msg.register_io_surface.io_surface_port.name; | |
274 int io_surface_id = msg.register_io_surface.io_surface_id; | |
275 int client_id = msg.register_io_surface.client_id; | |
276 | |
277 bool result = broker_->RegisterIOSurface(child_pid, io_surface_id, | |
278 client_id, io_surface_port); | |
279 | |
280 MachBroker_RegisterIOSurfaceReplyMsg reply; | |
281 bzero(&reply, sizeof(reply)); | |
282 reply.header.msgh_bits = MACH_MSGH_BITS_REMOTE(msg.header.msgh_bits); | |
283 reply.header.msgh_remote_port = msg.header.msgh_remote_port; | |
284 reply.header.msgh_size = sizeof(reply); | |
285 reply.result = result; | |
286 kern_return_t kr = mach_msg( | |
287 &reply.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, sizeof(reply), | |
288 0, MACH_PORT_NULL, 100 /*milliseconds*/, MACH_PORT_NULL); | |
289 if (kr != KERN_SUCCESS) { | |
290 MACH_LOG(ERROR, kr) << "mach_msg"; | |
291 } | |
292 | |
293 } break; | |
294 case kMachBroker_UnregisterIOSurfaceId: { | |
295 int io_surface_id = msg.unregister_io_surface.io_surface_id; | |
296 int client_id = msg.unregister_io_surface.client_id; | |
297 | |
298 broker_->UnregisterIOSurface(child_pid, io_surface_id, client_id); | |
299 } break; | |
300 case kMachBroker_AcquireIOSurfaceId: { | |
301 int io_surface_id = msg.acquire_io_surface.io_surface_id; | |
302 | |
303 mach_port_t io_surface_port = | |
304 broker_->AcquireIOSurface(child_pid, io_surface_id); | |
305 | |
306 MachBroker_AcquireIOSurfaceReplyMsg reply; | |
307 bzero(&reply, sizeof(reply)); | |
308 reply.header.msgh_bits = MACH_MSGH_BITS_REMOTE(msg.header.msgh_bits) | | |
309 MACH_MSGH_BITS_COMPLEX; | |
310 reply.header.msgh_remote_port = msg.header.msgh_remote_port; | |
311 reply.header.msgh_size = sizeof(reply); | |
312 reply.body.msgh_descriptor_count = 1; | |
313 reply.io_surface_port.name = io_surface_port; | |
314 reply.io_surface_port.disposition = MACH_MSG_TYPE_COPY_SEND; | |
315 reply.io_surface_port.type = MACH_MSG_PORT_DESCRIPTOR; | |
316 kern_return_t kr = mach_msg( | |
317 &reply.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, sizeof(reply), | |
318 0, MACH_PORT_NULL, 100 /*milliseconds*/, MACH_PORT_NULL); | |
319 if (kr != KERN_SUCCESS) { | |
320 MACH_LOG(ERROR, kr) << "mach_msg"; | |
321 } | |
322 } break; | |
323 } | |
120 } | 324 } |
121 | 325 |
122 MACH_LOG(ERROR, kr) << "mach_msg"; | 326 MACH_LOG(ERROR, kr) << "mach_msg"; |
123 } | 327 } |
124 | 328 |
125 private: | 329 private: |
126 // The MachBroker to use when new child task rights are received. Can be | 330 // The MachBroker to use when new child task rights are received. Can be |
127 // NULL. | 331 // NULL. |
128 MachBroker* broker_; // weak | 332 MachBroker* broker_; // weak |
129 | 333 |
130 base::mac::ScopedMachReceiveRight server_port_; | 334 base::mac::ScopedMachReceiveRight server_port_; |
131 | 335 |
132 DISALLOW_COPY_AND_ASSIGN(MachListenerThreadDelegate); | 336 DISALLOW_COPY_AND_ASSIGN(MachListenerThreadDelegate); |
133 }; | 337 }; |
134 | 338 |
339 MachBroker::MachPortSet::MachPortSet() | |
340 : is_gpu_process(false), task_port(MACH_PORT_NULL) { | |
341 } | |
342 | |
343 MachBroker::MachPortSet::MachPortSet(bool is_gpu_process) | |
344 : is_gpu_process(is_gpu_process), task_port(MACH_PORT_NULL) { | |
345 } | |
346 | |
347 MachBroker::MachPortSet::~MachPortSet() { | |
348 } | |
349 | |
135 bool MachBroker::ChildSendTaskPortToParent() { | 350 bool MachBroker::ChildSendTaskPortToParent() { |
136 // Look up the named MachBroker port that's been registered with the | 351 base::AutoLock lock(g_child_lock.Get()); |
137 // bootstrap server. | 352 |
138 mach_port_t parent_port; | 353 mach_port_t child_send_port = g_child_send_port.Get(); |
139 kern_return_t kr = bootstrap_look_up(bootstrap_port, | 354 if (child_send_port == MACH_PORT_NULL) |
140 const_cast<char*>(GetMachPortName().c_str()), &parent_port); | |
141 if (kr != KERN_SUCCESS) { | |
142 BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up"; | |
143 return false; | 355 return false; |
144 } | 356 |
145 base::mac::ScopedMachSendRight scoped_right(parent_port); | 357 // Make sure we have valid receive port before we send the check in message. |
358 mach_port_t child_receive_port = g_child_receive_port.Get(); | |
359 if (child_receive_port == MACH_PORT_NULL) | |
360 return false; | |
146 | 361 |
147 // Create the check in message. This will copy a send right on this process' | 362 // Create the check in message. This will copy a send right on this process' |
148 // (the child's) task port and send it to the parent. | 363 // (the child's) task port and send it to the parent. |
149 MachBroker_ChildSendMsg msg; | 364 MachBroker_ChildMsg msg; |
150 bzero(&msg, sizeof(msg)); | 365 bzero(&msg, sizeof(msg)); |
151 msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND) | | 366 msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND) | |
152 MACH_MSGH_BITS_COMPLEX; | 367 MACH_MSGH_BITS_COMPLEX; |
153 msg.header.msgh_remote_port = parent_port; | 368 msg.header.msgh_remote_port = child_send_port; |
154 msg.header.msgh_size = sizeof(msg); | 369 msg.header.msgh_size = sizeof(msg); |
370 msg.header.msgh_id = kMachBroker_ChildId; | |
155 msg.body.msgh_descriptor_count = 1; | 371 msg.body.msgh_descriptor_count = 1; |
156 msg.child_task_port.name = mach_task_self(); | 372 msg.child_task_port.name = mach_task_self(); |
157 msg.child_task_port.disposition = MACH_MSG_TYPE_PORT_SEND; | 373 msg.child_task_port.disposition = MACH_MSG_TYPE_PORT_SEND; |
158 msg.child_task_port.type = MACH_MSG_PORT_DESCRIPTOR; | 374 msg.child_task_port.type = MACH_MSG_PORT_DESCRIPTOR; |
159 | 375 |
160 kr = mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, sizeof(msg), | 376 kern_return_t kr = |
161 0, MACH_PORT_NULL, 100 /*milliseconds*/, MACH_PORT_NULL); | 377 mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, sizeof(msg), 0, |
378 MACH_PORT_NULL, 100 /*milliseconds*/, MACH_PORT_NULL); | |
162 if (kr != KERN_SUCCESS) { | 379 if (kr != KERN_SUCCESS) { |
163 MACH_LOG(ERROR, kr) << "mach_msg"; | 380 MACH_LOG(ERROR, kr) << "mach_msg"; |
164 return false; | 381 return false; |
165 } | 382 } |
166 | 383 |
167 return true; | 384 return true; |
168 } | 385 } |
169 | 386 |
387 bool MachBroker::ChildRegisterIOSurfaceWithParent(int io_surface_id, | |
388 int client_id, | |
389 mach_port_t io_surface_port) { | |
390 base::AutoLock lock(g_child_lock.Get()); | |
391 | |
392 mach_port_t child_receive_port = g_child_receive_port.Get(); | |
393 | |
394 // Deallocate the right after sending a copy to the parent. | |
395 base::mac::ScopedMachSendRight io_surface_send_right(io_surface_port); | |
396 | |
397 union { | |
398 MachBroker_RegisterIOSurfaceMsg request; | |
399 MachBroker_RegisterIOSurfaceReplyRecvMsg reply; | |
400 } msg; | |
401 bzero(&msg, sizeof(msg)); | |
402 msg.request.header.msgh_bits = | |
403 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) | | |
404 MACH_MSGH_BITS_COMPLEX; | |
405 msg.request.header.msgh_remote_port = g_child_send_port.Get(); | |
406 msg.request.header.msgh_local_port = child_receive_port; | |
407 msg.request.header.msgh_size = sizeof(msg.request); | |
408 msg.request.header.msgh_id = kMachBroker_RegisterIOSurfaceId; | |
409 msg.request.body.msgh_descriptor_count = 1; | |
410 msg.request.io_surface_port.name = io_surface_port; | |
411 msg.request.io_surface_port.disposition = MACH_MSG_TYPE_COPY_SEND; | |
412 msg.request.io_surface_port.type = MACH_MSG_PORT_DESCRIPTOR; | |
413 msg.request.io_surface_id = io_surface_id; | |
414 msg.request.client_id = client_id; | |
415 | |
416 kern_return_t kr = | |
417 mach_msg(&msg.request.header, MACH_SEND_MSG | MACH_RCV_MSG, | |
418 sizeof(msg.request), sizeof(msg.reply), child_receive_port, | |
419 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
420 if (kr != KERN_SUCCESS) { | |
421 MACH_LOG(ERROR, kr) << "mach_msg"; | |
422 return false; | |
423 } | |
424 | |
425 return msg.reply.result; | |
426 } | |
427 | |
428 bool MachBroker::ChildUnregisterIOSurfaceWithParent(int io_surface_id, | |
429 int client_id) { | |
430 base::AutoLock lock(g_child_lock.Get()); | |
431 | |
432 MachBroker_UnregisterIOSurfaceMsg msg; | |
433 bzero(&msg, sizeof(msg)); | |
434 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); | |
435 msg.header.msgh_remote_port = g_child_send_port.Get(); | |
436 msg.header.msgh_local_port = MACH_PORT_NULL; | |
437 msg.header.msgh_size = sizeof(msg); | |
438 msg.header.msgh_id = kMachBroker_UnregisterIOSurfaceId; | |
439 msg.io_surface_id = io_surface_id; | |
440 msg.client_id = client_id; | |
441 | |
442 kern_return_t kr = | |
443 mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, sizeof(msg), 0, | |
444 MACH_PORT_NULL, 100 /*milliseconds*/, MACH_PORT_NULL); | |
445 if (kr != KERN_SUCCESS) { | |
446 MACH_LOG(ERROR, kr) << "mach_msg"; | |
447 return false; | |
448 } | |
449 | |
450 return true; | |
451 } | |
452 | |
453 mach_port_t MachBroker::ChildAcquireIOSurfaceFromParent(int io_surface_id) { | |
454 base::AutoLock lock(g_child_lock.Get()); | |
455 | |
456 mach_port_t child_receive_port = g_child_receive_port.Get(); | |
457 | |
458 union { | |
459 MachBroker_AcquireIOSurfaceMsg request; | |
460 MachBroker_AcquireIOSurfaceReplyRecvMsg reply; | |
461 } msg; | |
462 bzero(&msg, sizeof(msg)); | |
463 msg.request.header.msgh_bits = | |
464 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); | |
465 msg.request.header.msgh_remote_port = g_child_send_port.Get(); | |
466 msg.request.header.msgh_local_port = child_receive_port; | |
467 msg.request.header.msgh_size = sizeof(msg.request); | |
468 msg.request.header.msgh_id = kMachBroker_AcquireIOSurfaceId; | |
469 msg.request.io_surface_id = io_surface_id; | |
470 | |
471 kern_return_t kr = | |
472 mach_msg(&msg.request.header, MACH_SEND_MSG | MACH_RCV_MSG, | |
473 sizeof(msg.request), sizeof(msg.reply), child_receive_port, | |
474 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
475 if (kr != KERN_SUCCESS) { | |
476 MACH_LOG(ERROR, kr) << "mach_msg"; | |
477 return MACH_PORT_NULL; | |
478 } | |
479 | |
480 return msg.reply.io_surface_port.name; | |
481 } | |
482 | |
170 MachBroker* MachBroker::GetInstance() { | 483 MachBroker* MachBroker::GetInstance() { |
171 return Singleton<MachBroker, LeakySingletonTraits<MachBroker> >::get(); | 484 return Singleton<MachBroker, LeakySingletonTraits<MachBroker> >::get(); |
172 } | 485 } |
173 | 486 |
174 base::Lock& MachBroker::GetLock() { | 487 base::Lock& MachBroker::GetLock() { |
175 return lock_; | 488 return lock_; |
176 } | 489 } |
177 | 490 |
178 void MachBroker::EnsureRunning() { | 491 void MachBroker::EnsureRunning() { |
179 lock_.AssertAcquired(); | 492 lock_.AssertAcquired(); |
180 | 493 |
181 if (!listener_thread_started_) { | 494 if (!listener_thread_started_) { |
182 listener_thread_started_ = true; | 495 listener_thread_started_ = true; |
183 | 496 |
184 BrowserThread::PostTask( | 497 BrowserThread::PostTask( |
185 BrowserThread::UI, FROM_HERE, | 498 BrowserThread::UI, FROM_HERE, |
186 base::Bind(&MachBroker::RegisterNotifications, base::Unretained(this))); | 499 base::Bind(&MachBroker::RegisterNotifications, base::Unretained(this))); |
187 | 500 |
188 // Intentional leak. This thread is never joined or reaped. | 501 // Intentional leak. This thread is never joined or reaped. |
189 MachListenerThreadDelegate* thread = new MachListenerThreadDelegate(this); | 502 MachListenerThreadDelegate* thread = new MachListenerThreadDelegate(this); |
190 if (thread->Init()) { | 503 if (thread->Init()) { |
191 base::PlatformThread::CreateNonJoinable(0, thread); | 504 base::PlatformThread::CreateNonJoinable(0, thread); |
192 } else { | 505 } else { |
193 LOG(ERROR) << "Failed to initialize the MachListenerThreadDelegate"; | 506 LOG(ERROR) << "Failed to initialize the MachListenerThreadDelegate"; |
194 } | 507 } |
195 } | 508 } |
196 } | 509 } |
197 | 510 |
198 void MachBroker::AddPlaceholderForPid(base::ProcessHandle pid, | 511 void MachBroker::AddPlaceholderForPid(base::ProcessHandle pid, |
199 int child_process_id) { | 512 int child_process_id, |
513 bool is_gpu_process) { | |
200 lock_.AssertAcquired(); | 514 lock_.AssertAcquired(); |
201 | 515 |
202 DCHECK_EQ(0u, mach_map_.count(pid)); | 516 DCHECK_EQ(0u, mach_map_.count(pid)); |
203 mach_map_[pid] = MACH_PORT_NULL; | 517 mach_map_[pid] = MachPortSet(is_gpu_process); |
204 child_process_id_map_[child_process_id] = pid; | 518 child_process_id_map_[child_process_id] = pid; |
205 } | 519 } |
206 | 520 |
207 mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const { | 521 mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const { |
208 base::AutoLock lock(lock_); | 522 base::AutoLock lock(lock_); |
209 MachBroker::MachMap::const_iterator it = mach_map_.find(pid); | 523 MachBroker::MachMap::const_iterator it = mach_map_.find(pid); |
210 if (it == mach_map_.end()) | 524 if (it == mach_map_.end()) |
211 return MACH_PORT_NULL; | 525 return MACH_PORT_NULL; |
212 return it->second; | 526 return it->second.task_port; |
213 } | 527 } |
214 | 528 |
215 void MachBroker::BrowserChildProcessHostDisconnected( | 529 void MachBroker::BrowserChildProcessHostDisconnected( |
216 const ChildProcessData& data) { | 530 const ChildProcessData& data) { |
217 InvalidateChildProcessId(data.id); | 531 InvalidateChildProcessId(data.id); |
218 } | 532 } |
219 | 533 |
220 void MachBroker::BrowserChildProcessCrashed(const ChildProcessData& data, | 534 void MachBroker::BrowserChildProcessCrashed(const ChildProcessData& data, |
221 int exit_code) { | 535 int exit_code) { |
222 InvalidateChildProcessId(data.id); | 536 InvalidateChildProcessId(data.id); |
(...skipping 24 matching lines...) Expand all Loading... | |
247 mach_port_t task_port) { | 561 mach_port_t task_port) { |
248 lock_.AssertAcquired(); | 562 lock_.AssertAcquired(); |
249 | 563 |
250 MachMap::iterator it = mach_map_.find(pid); | 564 MachMap::iterator it = mach_map_.find(pid); |
251 if (it == mach_map_.end()) { | 565 if (it == mach_map_.end()) { |
252 // Do nothing for unknown pids. | 566 // Do nothing for unknown pids. |
253 LOG(ERROR) << "Unknown process " << pid << " is sending Mach IPC messages!"; | 567 LOG(ERROR) << "Unknown process " << pid << " is sending Mach IPC messages!"; |
254 return; | 568 return; |
255 } | 569 } |
256 | 570 |
257 DCHECK(it->second == MACH_PORT_NULL); | 571 if (it->second.task_port == MACH_PORT_NULL) |
258 if (it->second == MACH_PORT_NULL) | 572 it->second.task_port = task_port; |
259 it->second = task_port; | |
260 } | 573 } |
261 | 574 |
262 void MachBroker::InvalidateChildProcessId(int child_process_id) { | 575 void MachBroker::InvalidateChildProcessId(int child_process_id) { |
263 base::AutoLock lock(lock_); | 576 base::AutoLock lock(lock_); |
264 MachBroker::ChildProcessIdMap::iterator it = | 577 MachBroker::ChildProcessIdMap::iterator it = |
265 child_process_id_map_.find(child_process_id); | 578 child_process_id_map_.find(child_process_id); |
266 if (it == child_process_id_map_.end()) | 579 if (it == child_process_id_map_.end()) |
267 return; | 580 return; |
268 | 581 |
269 MachMap::iterator mach_it = mach_map_.find(it->second); | 582 MachMap::iterator mach_it = mach_map_.find(it->second); |
270 if (mach_it != mach_map_.end()) { | 583 if (mach_it != mach_map_.end()) { |
271 kern_return_t kr = mach_port_deallocate(mach_task_self(), | 584 kern_return_t kr = |
272 mach_it->second); | 585 mach_port_deallocate(mach_task_self(), mach_it->second.task_port); |
273 MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; | 586 MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; |
587 for (const auto& io_surface_port : mach_it->second.io_surface_ports) { | |
588 kr = mach_port_deallocate(mach_task_self(), io_surface_port.second); | |
589 MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; | |
590 } | |
274 mach_map_.erase(mach_it); | 591 mach_map_.erase(mach_it); |
275 } | 592 } |
276 child_process_id_map_.erase(it); | 593 child_process_id_map_.erase(it); |
277 } | 594 } |
278 | 595 |
279 // static | 596 bool MachBroker::RegisterIOSurface(base::ProcessHandle pid, |
280 std::string MachBroker::GetMachPortName() { | 597 int io_surface_id, |
281 const base::CommandLine* command_line = | 598 int client_id, |
282 base::CommandLine::ForCurrentProcess(); | 599 mach_port_t io_surface_port) { |
283 const bool is_child = command_line->HasSwitch(switches::kProcessType); | 600 lock_.AssertAcquired(); |
284 | 601 |
285 // In non-browser (child) processes, use the parent's pid. | 602 MachMap::iterator mach_it = mach_map_.find(pid); |
286 const pid_t pid = is_child ? getppid() : getpid(); | 603 if (mach_it == mach_map_.end()) { |
287 return base::StringPrintf("%s.rohitfork.%d", base::mac::BaseBundleID(), pid); | 604 // Do nothing for unknown pids. |
605 LOG(ERROR) << "Unknown process " << pid << " is sending Mach IPC messages!"; | |
606 return false; | |
607 } | |
608 | |
609 if (!mach_it->second.is_gpu_process) { | |
610 LOG(ERROR) << "Illegal message from non-GPU process!"; | |
611 return false; | |
612 } | |
613 | |
614 ChildProcessIdMap::iterator it = child_process_id_map_.find(client_id); | |
615 if (it == child_process_id_map_.end()) | |
616 return false; | |
617 | |
618 MachMap::iterator client_it = mach_map_.find(it->second); | |
619 if (client_it == mach_map_.end()) { | |
620 LOG(ERROR) << "Unknown client process " << it->second; | |
621 return false; | |
622 } | |
623 | |
624 if (client_it->second.io_surface_ports.count(io_surface_id)) { | |
625 LOG(ERROR) << "IOSurface " << io_surface_id << " already exists!"; | |
626 return false; | |
627 } | |
628 | |
629 client_it->second.io_surface_ports[io_surface_id] = io_surface_port; | |
630 return true; | |
631 } | |
632 | |
633 void MachBroker::UnregisterIOSurface(base::ProcessHandle pid, | |
634 int io_surface_id, | |
635 int client_id) { | |
636 lock_.AssertAcquired(); | |
637 | |
638 MachMap::iterator mach_it = mach_map_.find(pid); | |
639 if (mach_it == mach_map_.end()) { | |
640 // Do nothing for unknown pids. | |
641 LOG(ERROR) << "Unknown process " << pid << " is sending Mach IPC messages!"; | |
642 return; | |
643 } | |
644 | |
645 if (!mach_it->second.is_gpu_process) { | |
646 LOG(ERROR) << "Illegal message from non-GPU process!"; | |
647 return; | |
648 } | |
649 | |
650 ChildProcessIdMap::iterator it = child_process_id_map_.find(client_id); | |
651 if (it == child_process_id_map_.end()) | |
652 return; | |
653 | |
654 mach_it = mach_map_.find(it->second); | |
655 if (mach_it != mach_map_.end()) { | |
656 auto io_surface_mach_it = | |
657 mach_it->second.io_surface_ports.find(io_surface_id); | |
658 if (io_surface_mach_it != mach_it->second.io_surface_ports.end()) { | |
659 kern_return_t kr = | |
660 mach_port_deallocate(mach_task_self(), io_surface_mach_it->second); | |
661 MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; | |
662 mach_it->second.io_surface_ports.erase(io_surface_mach_it); | |
663 } | |
664 } | |
665 } | |
666 | |
667 mach_port_t MachBroker::AcquireIOSurface(base::ProcessHandle pid, | |
668 int io_surface_id) { | |
669 lock_.AssertAcquired(); | |
670 | |
671 MachMap::iterator it = mach_map_.find(pid); | |
672 if (it == mach_map_.end()) { | |
673 // Do nothing for unknown pids. | |
674 LOG(ERROR) << "Unknown process " << pid << " is sending Mach IPC messages!"; | |
675 return MACH_PORT_NULL; | |
676 } | |
677 | |
678 auto io_surface_mach_it = it->second.io_surface_ports.find(io_surface_id); | |
679 if (io_surface_mach_it == it->second.io_surface_ports.end()) { | |
680 LOG(ERROR) << "Invalid Id for IOSurface " << io_surface_id; | |
681 return MACH_PORT_NULL; | |
682 } | |
683 | |
684 return io_surface_mach_it->second; | |
288 } | 685 } |
289 | 686 |
290 void MachBroker::RegisterNotifications() { | 687 void MachBroker::RegisterNotifications() { |
291 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED, | 688 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED, |
292 NotificationService::AllBrowserContextsAndSources()); | 689 NotificationService::AllBrowserContextsAndSources()); |
293 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 690 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
294 NotificationService::AllBrowserContextsAndSources()); | 691 NotificationService::AllBrowserContextsAndSources()); |
295 | 692 |
296 // No corresponding StopObservingBrowserChildProcesses, | 693 // No corresponding StopObservingBrowserChildProcesses, |
297 // we leak this singleton. | 694 // we leak this singleton. |
298 BrowserChildProcessObserver::Add(this); | 695 BrowserChildProcessObserver::Add(this); |
299 } | 696 } |
300 | 697 |
301 } // namespace content | 698 } // namespace content |
OLD | NEW |