OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "mojo/edk/system/node_controller.h" | 5 #include "mojo/edk/system/node_controller.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/location.h" | 11 #include "base/location.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
15 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
16 #include "base/process/process_handle.h" | 16 #include "base/process/process_handle.h" |
17 #include "crypto/random.h" | 17 #include "crypto/random.h" |
18 #include "mojo/edk/embedder/embedder_internal.h" | 18 #include "mojo/edk/embedder/embedder_internal.h" |
19 #include "mojo/edk/embedder/platform_channel_pair.h" | 19 #include "mojo/edk/embedder/platform_channel_pair.h" |
20 #include "mojo/edk/system/broker.h" | 20 #include "mojo/edk/system/broker.h" |
21 #include "mojo/edk/system/broker_host.h" | 21 #include "mojo/edk/system/broker_host.h" |
22 #include "mojo/edk/system/core.h" | 22 #include "mojo/edk/system/core.h" |
23 #include "mojo/edk/system/ports_message.h" | 23 #include "mojo/edk/system/ports_message.h" |
24 | 24 |
| 25 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 26 #include "mojo/edk/system/mach_port_relay.h" |
| 27 #endif |
| 28 |
25 namespace mojo { | 29 namespace mojo { |
26 namespace edk { | 30 namespace edk { |
27 | 31 |
28 namespace { | 32 namespace { |
29 | 33 |
30 template <typename T> | 34 template <typename T> |
31 void GenerateRandomName(T* out) { crypto::RandBytes(out, sizeof(T)); } | 35 void GenerateRandomName(T* out) { crypto::RandBytes(out, sizeof(T)); } |
32 | 36 |
33 ports::NodeName GetRandomNodeName() { | 37 ports::NodeName GetRandomNodeName() { |
34 ports::NodeName name; | 38 ports::NodeName name; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 | 104 |
101 NodeController::~NodeController() {} | 105 NodeController::~NodeController() {} |
102 | 106 |
103 NodeController::NodeController(Core* core) | 107 NodeController::NodeController(Core* core) |
104 : core_(core), | 108 : core_(core), |
105 name_(GetRandomNodeName()), | 109 name_(GetRandomNodeName()), |
106 node_(new ports::Node(name_, this)) { | 110 node_(new ports::Node(name_, this)) { |
107 DVLOG(1) << "Initializing node " << name_; | 111 DVLOG(1) << "Initializing node " << name_; |
108 } | 112 } |
109 | 113 |
| 114 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 115 void NodeController::CreateMachPortRelay( |
| 116 base::PortProvider* port_provider) { |
| 117 base::AutoLock lock(mach_port_relay_lock_); |
| 118 DCHECK(!mach_port_relay_); |
| 119 mach_port_relay_.reset(new MachPortRelay(port_provider)); |
| 120 } |
| 121 #endif |
| 122 |
110 void NodeController::SetIOTaskRunner( | 123 void NodeController::SetIOTaskRunner( |
111 scoped_refptr<base::TaskRunner> task_runner) { | 124 scoped_refptr<base::TaskRunner> task_runner) { |
112 io_task_runner_ = task_runner; | 125 io_task_runner_ = task_runner; |
113 ThreadDestructionObserver::Create( | 126 ThreadDestructionObserver::Create( |
114 io_task_runner_, | 127 io_task_runner_, |
115 base::Bind(&NodeController::DropAllPeers, base::Unretained(this))); | 128 base::Bind(&NodeController::DropAllPeers, base::Unretained(this))); |
116 } | 129 } |
117 | 130 |
118 void NodeController::ConnectToChild(base::ProcessHandle process_handle, | 131 void NodeController::ConnectToChild(base::ProcessHandle process_handle, |
119 ScopedPlatformHandle platform_handle) { | 132 ScopedPlatformHandle platform_handle) { |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 channel->SetRemoteProcessHandle(process_handle); | 284 channel->SetRemoteProcessHandle(process_handle); |
272 channel->Start(); | 285 channel->Start(); |
273 | 286 |
274 channel->AcceptChild(name_, token); | 287 channel->AcceptChild(name_, token); |
275 } | 288 } |
276 | 289 |
277 void NodeController::ConnectToParentOnIOThread( | 290 void NodeController::ConnectToParentOnIOThread( |
278 ScopedPlatformHandle platform_handle) { | 291 ScopedPlatformHandle platform_handle) { |
279 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | 292 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
280 | 293 |
281 base::AutoLock lock(parent_lock_); | 294 { |
282 DCHECK(parent_name_ == ports::kInvalidNodeName); | 295 base::AutoLock lock(parent_lock_); |
| 296 DCHECK(parent_name_ == ports::kInvalidNodeName); |
283 | 297 |
284 // At this point we don't know the parent's name, so we can't yet insert it | 298 // At this point we don't know the parent's name, so we can't yet insert it |
285 // into our |peers_| map. That will happen as soon as we receive an | 299 // into our |peers_| map. That will happen as soon as we receive an |
286 // AcceptChild message from them. | 300 // AcceptChild message from them. |
287 bootstrap_parent_channel_ = | 301 bootstrap_parent_channel_ = |
288 NodeChannel::Create(this, std::move(platform_handle), io_task_runner_); | 302 NodeChannel::Create(this, std::move(platform_handle), io_task_runner_); |
| 303 } |
289 bootstrap_parent_channel_->Start(); | 304 bootstrap_parent_channel_->Start(); |
290 } | 305 } |
291 | 306 |
292 scoped_refptr<NodeChannel> NodeController::GetPeerChannel( | 307 scoped_refptr<NodeChannel> NodeController::GetPeerChannel( |
293 const ports::NodeName& name) { | 308 const ports::NodeName& name) { |
294 base::AutoLock lock(peers_lock_); | 309 base::AutoLock lock(peers_lock_); |
295 auto it = peers_.find(name); | 310 auto it = peers_.find(name); |
296 if (it == peers_.end()) | 311 if (it == peers_.end()) |
297 return nullptr; | 312 return nullptr; |
298 return it->second; | 313 return it->second; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 if (!peer || !peer->HasRemoteProcessHandle()) { | 414 if (!peer || !peer->HasRemoteProcessHandle()) { |
400 if (broker) { | 415 if (broker) { |
401 broker->RelayPortsMessage(name, std::move(channel_message)); | 416 broker->RelayPortsMessage(name, std::move(channel_message)); |
402 } else { | 417 } else { |
403 base::AutoLock lock(broker_lock_); | 418 base::AutoLock lock(broker_lock_); |
404 pending_relay_messages_[name].emplace(std::move(channel_message)); | 419 pending_relay_messages_[name].emplace(std::move(channel_message)); |
405 } | 420 } |
406 return; | 421 return; |
407 } | 422 } |
408 } | 423 } |
409 #endif | 424 #elif defined(OS_MACOSX) && !defined(OS_IOS) |
| 425 if (channel_message->has_mach_ports()) { |
| 426 // Messages containing Mach ports are always routed through the broker, even |
| 427 // if the broker process is the intended recipient. |
| 428 bool use_broker = false; |
| 429 { |
| 430 base::AutoLock lock(parent_lock_); |
| 431 use_broker = (bootstrap_parent_channel_ || |
| 432 parent_name_ != ports::kInvalidNodeName); |
| 433 } |
| 434 if (use_broker) { |
| 435 scoped_refptr<NodeChannel> broker = GetBrokerChannel(); |
| 436 if (broker) { |
| 437 broker->RelayPortsMessage(name, std::move(channel_message)); |
| 438 } else { |
| 439 base::AutoLock lock(broker_lock_); |
| 440 pending_relay_messages_[name].emplace(std::move(channel_message)); |
| 441 } |
| 442 return; |
| 443 } |
| 444 } |
| 445 #endif // defined(OS_WIN) |
410 | 446 |
411 if (peer) { | 447 if (peer) { |
412 peer->PortsMessage(std::move(channel_message)); | 448 peer->PortsMessage(std::move(channel_message)); |
413 return; | 449 return; |
414 } | 450 } |
415 | 451 |
416 // If we don't know who the peer is, queue the message for delivery. If this | 452 // If we don't know who the peer is, queue the message for delivery. If this |
417 // is the first message queued for the peer, we also ask the broker to | 453 // is the first message queued for the peer, we also ask the broker to |
418 // introduce us to them. | 454 // introduce us to them. |
419 | 455 |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node, | 688 void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node, |
653 const ports::NodeName& client_name, | 689 const ports::NodeName& client_name, |
654 ScopedPlatformHandle broker_channel) { | 690 ScopedPlatformHandle broker_channel) { |
655 scoped_refptr<NodeChannel> client = GetPeerChannel(client_name); | 691 scoped_refptr<NodeChannel> client = GetPeerChannel(client_name); |
656 if (!client) { | 692 if (!client) { |
657 DLOG(ERROR) << "BrokerClientAdded for unknown child " << client_name; | 693 DLOG(ERROR) << "BrokerClientAdded for unknown child " << client_name; |
658 return; | 694 return; |
659 } | 695 } |
660 | 696 |
661 // This should have come from our own broker. | 697 // This should have come from our own broker. |
662 if(GetBrokerChannel() != GetPeerChannel(from_node)) { | 698 if (GetBrokerChannel() != GetPeerChannel(from_node)) { |
663 DLOG(ERROR) << "BrokerClientAdded from non-broker node " << from_node; | 699 DLOG(ERROR) << "BrokerClientAdded from non-broker node " << from_node; |
664 return; | 700 return; |
665 } | 701 } |
666 | 702 |
667 DVLOG(1) << "Child " << client_name << " accepted by broker " << from_node; | 703 DVLOG(1) << "Child " << client_name << " accepted by broker " << from_node; |
668 | 704 |
669 client->AcceptBrokerClient(from_node, std::move(broker_channel)); | 705 client->AcceptBrokerClient(from_node, std::move(broker_channel)); |
670 } | 706 } |
671 | 707 |
672 void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node, | 708 void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
720 | 756 |
721 // Feed the broker any pending children of our own. | 757 // Feed the broker any pending children of our own. |
722 while (!pending_broker_clients.empty()) { | 758 while (!pending_broker_clients.empty()) { |
723 const ports::NodeName& child_name = pending_broker_clients.front(); | 759 const ports::NodeName& child_name = pending_broker_clients.front(); |
724 auto it = pending_children_.find(child_name); | 760 auto it = pending_children_.find(child_name); |
725 DCHECK(it != pending_children_.end()); | 761 DCHECK(it != pending_children_.end()); |
726 broker->AddBrokerClient(child_name, it->second->CopyRemoteProcessHandle()); | 762 broker->AddBrokerClient(child_name, it->second->CopyRemoteProcessHandle()); |
727 pending_broker_clients.pop(); | 763 pending_broker_clients.pop(); |
728 } | 764 } |
729 | 765 |
730 #if defined(OS_WIN) | 766 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) |
731 // Have the broker relay any messages we have waiting. | 767 // Have the broker relay any messages we have waiting. |
732 for (auto& entry : pending_relay_messages) { | 768 for (auto& entry : pending_relay_messages) { |
733 const ports::NodeName& destination = entry.first; | 769 const ports::NodeName& destination = entry.first; |
734 auto& message_queue = entry.second; | 770 auto& message_queue = entry.second; |
735 while (!message_queue.empty()) { | 771 while (!message_queue.empty()) { |
736 broker->RelayPortsMessage(destination, std::move(message_queue.front())); | 772 broker->RelayPortsMessage(destination, std::move(message_queue.front())); |
737 message_queue.pop(); | 773 message_queue.pop(); |
738 } | 774 } |
739 } | 775 } |
740 #endif | 776 #endif |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
829 return; | 865 return; |
830 } | 866 } |
831 | 867 |
832 scoped_refptr<NodeChannel> channel = | 868 scoped_refptr<NodeChannel> channel = |
833 NodeChannel::Create(this, std::move(channel_handle), io_task_runner_); | 869 NodeChannel::Create(this, std::move(channel_handle), io_task_runner_); |
834 | 870 |
835 DVLOG(1) << "Adding new peer " << name << " via parent introduction."; | 871 DVLOG(1) << "Adding new peer " << name << " via parent introduction."; |
836 AddPeer(name, channel, true /* start_channel */); | 872 AddPeer(name, channel, true /* start_channel */); |
837 } | 873 } |
838 | 874 |
839 #if defined(OS_WIN) | 875 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) |
840 void NodeController::OnRelayPortsMessage(const ports::NodeName& from_node, | 876 void NodeController::OnRelayPortsMessage(const ports::NodeName& from_node, |
841 base::ProcessHandle from_process, | 877 base::ProcessHandle from_process, |
842 const ports::NodeName& destination, | 878 const ports::NodeName& destination, |
843 Channel::MessagePtr message) { | 879 Channel::MessagePtr message) { |
| 880 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 881 |
844 if (GetBrokerChannel()) { | 882 if (GetBrokerChannel()) { |
845 // Only the broker should be asked to relay a message. | 883 // Only the broker should be asked to relay a message. |
846 LOG(ERROR) << "Non-broker refusing to relay message."; | 884 LOG(ERROR) << "Non-broker refusing to relay message."; |
847 DropPeer(from_node); | 885 DropPeer(from_node); |
848 return; | 886 return; |
849 } | 887 } |
850 | 888 |
851 // The parent should always know which process this came from. | 889 // The parent should always know which process this came from. |
852 DCHECK(from_process != base::kNullProcessHandle); | 890 DCHECK(from_process != base::kNullProcessHandle); |
853 | 891 |
| 892 #if defined(OS_WIN) |
854 // Rewrite the handles to this (the parent) process. If the message is | 893 // Rewrite the handles to this (the parent) process. If the message is |
855 // destined for another child process, the handles will be rewritten to that | 894 // destined for another child process, the handles will be rewritten to that |
856 // process before going out (see NodeChannel::WriteChannelMessage). | 895 // process before going out (see NodeChannel::WriteChannelMessage). |
857 // | 896 // |
858 // TODO: We could avoid double-duplication. | 897 // TODO: We could avoid double-duplication. |
859 if (!Channel::Message::RewriteHandles(from_process, | 898 if (!Channel::Message::RewriteHandles(from_process, |
860 base::GetCurrentProcessHandle(), | 899 base::GetCurrentProcessHandle(), |
861 message->handles(), | 900 message->handles(), |
862 message->num_handles())) { | 901 message->num_handles())) { |
863 DLOG(ERROR) << "Failed to relay one or more handles."; | 902 DLOG(ERROR) << "Failed to relay one or more handles."; |
864 } | 903 } |
| 904 #else |
| 905 MachPortRelay* relay = GetMachPortRelay(); |
| 906 if (!relay) { |
| 907 LOG(ERROR) << "Receiving Mach ports without a port relay from " |
| 908 << from_node << ". Dropping message."; |
| 909 return; |
| 910 } |
| 911 if (!relay->ExtractPortRights(message.get(), from_process)) { |
| 912 // NodeChannel should ensure that MachPortRelay is ready for the remote |
| 913 // process. At this point, if the port extraction failed, either something |
| 914 // went wrong in the mach stuff, or the remote process died. |
| 915 LOG(ERROR) << "Error on receiving Mach ports " << from_node |
| 916 << ". Dropping message."; |
| 917 return; |
| 918 } |
| 919 #endif // defined(OS_WIN) |
865 | 920 |
866 if (destination == name_) { | 921 if (destination == name_) { |
867 // Great, we can deliver this message locally. | 922 // Great, we can deliver this message locally. |
868 OnPortsMessage(std::move(message)); | 923 OnPortsMessage(std::move(message)); |
869 return; | 924 return; |
870 } | 925 } |
871 | 926 |
872 scoped_refptr<NodeChannel> peer = GetPeerChannel(destination); | 927 scoped_refptr<NodeChannel> peer = GetPeerChannel(destination); |
873 if (peer) | 928 if (peer) |
874 peer->PortsMessage(std::move(message)); | 929 peer->PortsMessage(std::move(message)); |
875 else | 930 else |
876 DLOG(ERROR) << "Dropping relay message for unknown node " << destination; | 931 DLOG(ERROR) << "Dropping relay message for unknown node " << destination; |
877 } | 932 } |
878 #endif | 933 #endif |
879 | 934 |
880 void NodeController::OnChannelError(const ports::NodeName& from_node) { | 935 void NodeController::OnChannelError(const ports::NodeName& from_node) { |
881 if (io_task_runner_->RunsTasksOnCurrentThread()) { | 936 if (io_task_runner_->RunsTasksOnCurrentThread()) { |
882 DropPeer(from_node); | 937 DropPeer(from_node); |
883 } else { | 938 } else { |
884 io_task_runner_->PostTask( | 939 io_task_runner_->PostTask( |
885 FROM_HERE, | 940 FROM_HERE, |
886 base::Bind(&NodeController::DropPeer, base::Unretained(this), | 941 base::Bind(&NodeController::DropPeer, base::Unretained(this), |
887 from_node)); | 942 from_node)); |
888 } | 943 } |
889 } | 944 } |
890 | 945 |
| 946 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 947 MachPortRelay* NodeController::GetMachPortRelay() { |
| 948 { |
| 949 base::AutoLock lock(parent_lock_); |
| 950 // Return null if we're not the root. |
| 951 if (bootstrap_parent_channel_ || parent_name_ != ports::kInvalidNodeName) |
| 952 return nullptr; |
| 953 } |
| 954 |
| 955 base::AutoLock lock(mach_port_relay_lock_); |
| 956 return mach_port_relay_.get(); |
| 957 } |
| 958 #endif |
| 959 |
891 void NodeController::DestroyOnIOThreadShutdown() { | 960 void NodeController::DestroyOnIOThreadShutdown() { |
892 destroy_on_io_thread_shutdown_ = true; | 961 destroy_on_io_thread_shutdown_ = true; |
893 } | 962 } |
894 | 963 |
895 void NodeController::AttemptShutdownIfRequested() { | 964 void NodeController::AttemptShutdownIfRequested() { |
896 base::Closure callback; | 965 base::Closure callback; |
897 { | 966 { |
898 base::AutoLock lock(shutdown_lock_); | 967 base::AutoLock lock(shutdown_lock_); |
899 if (shutdown_callback_.is_null()) | 968 if (shutdown_callback_.is_null()) |
900 return; | 969 return; |
901 if (!node_->CanShutdownCleanly(true /* allow_local_ports */)) { | 970 if (!node_->CanShutdownCleanly(true /* allow_local_ports */)) { |
902 DVLOG(2) << "Unable to cleanly shut down node " << name_ << "."; | 971 DVLOG(2) << "Unable to cleanly shut down node " << name_ << "."; |
903 return; | 972 return; |
904 } | 973 } |
905 callback = shutdown_callback_; | 974 callback = shutdown_callback_; |
906 shutdown_callback_.Reset(); | 975 shutdown_callback_.Reset(); |
907 } | 976 } |
908 | 977 |
909 DCHECK(!callback.is_null()); | 978 DCHECK(!callback.is_null()); |
910 | 979 |
911 callback.Run(); | 980 callback.Run(); |
912 } | 981 } |
913 | 982 |
914 } // namespace edk | 983 } // namespace edk |
915 } // namespace mojo | 984 } // namespace mojo |
OLD | NEW |