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