Chromium Code Reviews| 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 |