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::CreateMachPortRelayIfNeeded( |
| 116 base::PortProvider* port_provider) { |
| 117 base::AutoLock lock(mach_port_relay_lock_); |
| 118 DCHECK(!mach_port_relay_ || |
| 119 mach_port_relay_->port_provider() == port_provider); |
| 120 mach_port_relay_.reset(new MachPortRelay(port_provider)); |
| 121 } |
| 122 #endif |
| 123 |
110 void NodeController::SetIOTaskRunner( | 124 void NodeController::SetIOTaskRunner( |
111 scoped_refptr<base::TaskRunner> task_runner) { | 125 scoped_refptr<base::TaskRunner> task_runner) { |
112 io_task_runner_ = task_runner; | 126 io_task_runner_ = task_runner; |
113 ThreadDestructionObserver::Create( | 127 ThreadDestructionObserver::Create( |
114 io_task_runner_, | 128 io_task_runner_, |
115 base::Bind(&NodeController::DropAllPeers, base::Unretained(this))); | 129 base::Bind(&NodeController::DropAllPeers, base::Unretained(this))); |
116 } | 130 } |
117 | 131 |
118 void NodeController::ConnectToChild(base::ProcessHandle process_handle, | 132 void NodeController::ConnectToChild(base::ProcessHandle process_handle, |
119 ScopedPlatformHandle platform_handle) { | 133 ScopedPlatformHandle platform_handle) { |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 channel->SetRemoteProcessHandle(process_handle); | 278 channel->SetRemoteProcessHandle(process_handle); |
265 channel->Start(); | 279 channel->Start(); |
266 | 280 |
267 channel->AcceptChild(name_, token); | 281 channel->AcceptChild(name_, token); |
268 } | 282 } |
269 | 283 |
270 void NodeController::ConnectToParentOnIOThread( | 284 void NodeController::ConnectToParentOnIOThread( |
271 ScopedPlatformHandle platform_handle) { | 285 ScopedPlatformHandle platform_handle) { |
272 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | 286 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
273 | 287 |
274 base::AutoLock lock(parent_lock_); | 288 { |
275 DCHECK(parent_name_ == ports::kInvalidNodeName); | 289 base::AutoLock lock(parent_lock_); |
| 290 DCHECK(parent_name_ == ports::kInvalidNodeName); |
276 | 291 |
277 // At this point we don't know the parent's name, so we can't yet insert it | 292 // At this point we don't know the parent's name, so we can't yet insert it |
278 // into our |peers_| map. That will happen as soon as we receive an | 293 // into our |peers_| map. That will happen as soon as we receive an |
279 // AcceptChild message from them. | 294 // AcceptChild message from them. |
280 bootstrap_parent_channel_ = | 295 bootstrap_parent_channel_ = |
281 NodeChannel::Create(this, std::move(platform_handle), io_task_runner_); | 296 NodeChannel::Create(this, std::move(platform_handle), io_task_runner_); |
| 297 } |
282 bootstrap_parent_channel_->Start(); | 298 bootstrap_parent_channel_->Start(); |
283 } | 299 } |
284 | 300 |
285 scoped_refptr<NodeChannel> NodeController::GetPeerChannel( | 301 scoped_refptr<NodeChannel> NodeController::GetPeerChannel( |
286 const ports::NodeName& name) { | 302 const ports::NodeName& name) { |
287 base::AutoLock lock(peers_lock_); | 303 base::AutoLock lock(peers_lock_); |
288 auto it = peers_.find(name); | 304 auto it = peers_.find(name); |
289 if (it == peers_.end()) | 305 if (it == peers_.end()) |
290 return nullptr; | 306 return nullptr; |
291 return it->second; | 307 return it->second; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 if (!peer || !peer->HasRemoteProcessHandle()) { | 408 if (!peer || !peer->HasRemoteProcessHandle()) { |
393 if (broker) { | 409 if (broker) { |
394 broker->RelayPortsMessage(name, std::move(channel_message)); | 410 broker->RelayPortsMessage(name, std::move(channel_message)); |
395 } else { | 411 } else { |
396 base::AutoLock lock(broker_lock_); | 412 base::AutoLock lock(broker_lock_); |
397 pending_relay_messages_[name].emplace(std::move(channel_message)); | 413 pending_relay_messages_[name].emplace(std::move(channel_message)); |
398 } | 414 } |
399 return; | 415 return; |
400 } | 416 } |
401 } | 417 } |
402 #endif | 418 #elif defined(OS_MACOSX) && !defined(OS_IOS) |
| 419 if (channel_message->has_mach_ports()) { |
| 420 // Messages containing Mach ports are always routed through the broker, even |
| 421 // if the broker process is the intended recipient. |
| 422 bool use_broker = false; |
| 423 { |
| 424 base::AutoLock lock(parent_lock_); |
| 425 use_broker = (bootstrap_parent_channel_ || |
| 426 parent_name_ != ports::kInvalidNodeName); |
| 427 } |
| 428 if (use_broker) { |
| 429 scoped_refptr<NodeChannel> broker = GetBrokerChannel(); |
| 430 if (broker) { |
| 431 broker->RelayPortsMessage(name, std::move(channel_message)); |
| 432 } else { |
| 433 base::AutoLock lock(broker_lock_); |
| 434 pending_relay_messages_[name].emplace(std::move(channel_message)); |
| 435 } |
| 436 return; |
| 437 } |
| 438 } |
| 439 #endif // defined(OS_WIN) |
403 | 440 |
404 if (peer) { | 441 if (peer) { |
405 peer->PortsMessage(std::move(channel_message)); | 442 peer->PortsMessage(std::move(channel_message)); |
406 return; | 443 return; |
407 } | 444 } |
408 | 445 |
409 // If we don't know who the peer is, queue the message for delivery. If this | 446 // If we don't know who the peer is, queue the message for delivery. If this |
410 // is the first message queued for the peer, we also ask the broker to | 447 // is the first message queued for the peer, we also ask the broker to |
411 // introduce us to them. | 448 // introduce us to them. |
412 | 449 |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node, | 679 void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node, |
643 const ports::NodeName& client_name, | 680 const ports::NodeName& client_name, |
644 ScopedPlatformHandle broker_channel) { | 681 ScopedPlatformHandle broker_channel) { |
645 scoped_refptr<NodeChannel> client = GetPeerChannel(client_name); | 682 scoped_refptr<NodeChannel> client = GetPeerChannel(client_name); |
646 if (!client) { | 683 if (!client) { |
647 DLOG(ERROR) << "BrokerClientAdded for unknown child " << client_name; | 684 DLOG(ERROR) << "BrokerClientAdded for unknown child " << client_name; |
648 return; | 685 return; |
649 } | 686 } |
650 | 687 |
651 // This should have come from our own broker. | 688 // This should have come from our own broker. |
652 if(GetBrokerChannel() != GetPeerChannel(from_node)) { | 689 if (GetBrokerChannel() != GetPeerChannel(from_node)) { |
653 DLOG(ERROR) << "BrokerClientAdded from non-broker node " << from_node; | 690 DLOG(ERROR) << "BrokerClientAdded from non-broker node " << from_node; |
654 return; | 691 return; |
655 } | 692 } |
656 | 693 |
657 DVLOG(1) << "Child " << client_name << " accepted by broker " << from_node; | 694 DVLOG(1) << "Child " << client_name << " accepted by broker " << from_node; |
658 | 695 |
659 client->AcceptBrokerClient(from_node, std::move(broker_channel)); | 696 client->AcceptBrokerClient(from_node, std::move(broker_channel)); |
660 } | 697 } |
661 | 698 |
662 void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node, | 699 void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 | 747 |
711 // Feed the broker any pending children of our own. | 748 // Feed the broker any pending children of our own. |
712 while (!pending_broker_clients.empty()) { | 749 while (!pending_broker_clients.empty()) { |
713 const ports::NodeName& child_name = pending_broker_clients.front(); | 750 const ports::NodeName& child_name = pending_broker_clients.front(); |
714 auto it = pending_children_.find(child_name); | 751 auto it = pending_children_.find(child_name); |
715 DCHECK(it != pending_children_.end()); | 752 DCHECK(it != pending_children_.end()); |
716 broker->AddBrokerClient(child_name, it->second->CopyRemoteProcessHandle()); | 753 broker->AddBrokerClient(child_name, it->second->CopyRemoteProcessHandle()); |
717 pending_broker_clients.pop(); | 754 pending_broker_clients.pop(); |
718 } | 755 } |
719 | 756 |
720 #if defined(OS_WIN) | 757 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) |
721 // Have the broker relay any messages we have waiting. | 758 // Have the broker relay any messages we have waiting. |
722 for (auto& entry : pending_relay_messages) { | 759 for (auto& entry : pending_relay_messages) { |
723 const ports::NodeName& destination = entry.first; | 760 const ports::NodeName& destination = entry.first; |
724 auto& message_queue = entry.second; | 761 auto& message_queue = entry.second; |
725 while (!message_queue.empty()) { | 762 while (!message_queue.empty()) { |
726 broker->RelayPortsMessage(destination, std::move(message_queue.front())); | 763 broker->RelayPortsMessage(destination, std::move(message_queue.front())); |
727 message_queue.pop(); | 764 message_queue.pop(); |
728 } | 765 } |
729 } | 766 } |
730 #endif | 767 #endif |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 return; | 857 return; |
821 } | 858 } |
822 | 859 |
823 scoped_refptr<NodeChannel> channel = | 860 scoped_refptr<NodeChannel> channel = |
824 NodeChannel::Create(this, std::move(channel_handle), io_task_runner_); | 861 NodeChannel::Create(this, std::move(channel_handle), io_task_runner_); |
825 | 862 |
826 DVLOG(1) << "Adding new peer " << name << " via parent introduction."; | 863 DVLOG(1) << "Adding new peer " << name << " via parent introduction."; |
827 AddPeer(name, channel, true /* start_channel */); | 864 AddPeer(name, channel, true /* start_channel */); |
828 } | 865 } |
829 | 866 |
830 #if defined(OS_WIN) | 867 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) |
831 void NodeController::OnRelayPortsMessage(const ports::NodeName& from_node, | 868 void NodeController::OnRelayPortsMessage(const ports::NodeName& from_node, |
832 base::ProcessHandle from_process, | 869 base::ProcessHandle from_process, |
833 const ports::NodeName& destination, | 870 const ports::NodeName& destination, |
834 Channel::MessagePtr message) { | 871 Channel::MessagePtr message) { |
| 872 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 873 |
835 if (GetBrokerChannel()) { | 874 if (GetBrokerChannel()) { |
836 // Only the broker should be asked to relay a message. | 875 // Only the broker should be asked to relay a message. |
837 LOG(ERROR) << "Non-broker refusing to relay message."; | 876 LOG(ERROR) << "Non-broker refusing to relay message."; |
838 DropPeer(from_node); | 877 DropPeer(from_node); |
839 return; | 878 return; |
840 } | 879 } |
841 | 880 |
842 // The parent should always know which process this came from. | 881 // The parent should always know which process this came from. |
843 DCHECK(from_process != base::kNullProcessHandle); | 882 DCHECK(from_process != base::kNullProcessHandle); |
844 | 883 |
| 884 #if defined(OS_WIN) |
845 // Rewrite the handles to this (the parent) process. If the message is | 885 // Rewrite the handles to this (the parent) process. If the message is |
846 // destined for another child process, the handles will be rewritten to that | 886 // destined for another child process, the handles will be rewritten to that |
847 // process before going out (see NodeChannel::WriteChannelMessage). | 887 // process before going out (see NodeChannel::WriteChannelMessage). |
848 // | 888 // |
849 // TODO: We could avoid double-duplication. | 889 // TODO: We could avoid double-duplication. |
850 if (!Channel::Message::RewriteHandles(from_process, | 890 if (!Channel::Message::RewriteHandles(from_process, |
851 base::GetCurrentProcessHandle(), | 891 base::GetCurrentProcessHandle(), |
852 message->handles(), | 892 message->handles(), |
853 message->num_handles())) { | 893 message->num_handles())) { |
854 DLOG(ERROR) << "Failed to relay one or more handles."; | 894 DLOG(ERROR) << "Failed to relay one or more handles."; |
855 } | 895 } |
| 896 #else |
| 897 MachPortRelay* relay = GetMachPortRelay(); |
| 898 if (!relay) { |
| 899 LOG(ERROR) << "Receiving Mach ports without a port relay from " |
| 900 << from_node << ". Dropping message."; |
| 901 return; |
| 902 } |
| 903 if (!relay->ExtractPortRights(message.get(), from_process)) { |
| 904 // NodeChannel should ensure that MachPortRelay is ready for the remote |
| 905 // process. At this point, if the port extraction failed, either something |
| 906 // went wrong in the mach stuff, or the remote process died. |
| 907 LOG(ERROR) << "Error on receiving Mach ports " << from_node |
| 908 << ". Dropping message."; |
| 909 return; |
| 910 } |
| 911 #endif // defined(OS_WIN) |
856 | 912 |
857 if (destination == name_) { | 913 if (destination == name_) { |
858 // Great, we can deliver this message locally. | 914 // Great, we can deliver this message locally. |
859 OnPortsMessage(std::move(message)); | 915 OnPortsMessage(std::move(message)); |
860 return; | 916 return; |
861 } | 917 } |
862 | 918 |
863 scoped_refptr<NodeChannel> peer = GetPeerChannel(destination); | 919 scoped_refptr<NodeChannel> peer = GetPeerChannel(destination); |
864 if (peer) | 920 if (peer) |
865 peer->PortsMessage(std::move(message)); | 921 peer->PortsMessage(std::move(message)); |
866 else | 922 else |
867 DLOG(ERROR) << "Dropping relay message for unknown node " << destination; | 923 DLOG(ERROR) << "Dropping relay message for unknown node " << destination; |
868 } | 924 } |
869 #endif | 925 #endif |
870 | 926 |
871 void NodeController::OnChannelError(const ports::NodeName& from_node) { | 927 void NodeController::OnChannelError(const ports::NodeName& from_node) { |
872 if (io_task_runner_->RunsTasksOnCurrentThread()) { | 928 if (io_task_runner_->RunsTasksOnCurrentThread()) { |
873 DropPeer(from_node); | 929 DropPeer(from_node); |
874 } else { | 930 } else { |
875 io_task_runner_->PostTask( | 931 io_task_runner_->PostTask( |
876 FROM_HERE, | 932 FROM_HERE, |
877 base::Bind(&NodeController::DropPeer, base::Unretained(this), | 933 base::Bind(&NodeController::DropPeer, base::Unretained(this), |
878 from_node)); | 934 from_node)); |
879 } | 935 } |
880 } | 936 } |
881 | 937 |
| 938 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 939 MachPortRelay* NodeController::GetMachPortRelay() { |
| 940 { |
| 941 base::AutoLock lock(parent_lock_); |
| 942 // Return null if we're not the root. |
| 943 if (bootstrap_parent_channel_ || parent_name_ != ports::kInvalidNodeName) |
| 944 return nullptr; |
| 945 } |
| 946 |
| 947 base::AutoLock lock(mach_port_relay_lock_); |
| 948 return mach_port_relay_.get(); |
| 949 } |
| 950 #endif |
| 951 |
882 void NodeController::DestroyOnIOThreadShutdown() { | 952 void NodeController::DestroyOnIOThreadShutdown() { |
883 destroy_on_io_thread_shutdown_ = true; | 953 destroy_on_io_thread_shutdown_ = true; |
884 } | 954 } |
885 | 955 |
886 void NodeController::AttemptShutdownIfRequested() { | 956 void NodeController::AttemptShutdownIfRequested() { |
887 base::Closure callback; | 957 base::Closure callback; |
888 { | 958 { |
889 base::AutoLock lock(shutdown_lock_); | 959 base::AutoLock lock(shutdown_lock_); |
890 if (shutdown_callback_.is_null()) | 960 if (shutdown_callback_.is_null()) |
891 return; | 961 return; |
892 if (!node_->CanShutdownCleanly(true /* allow_local_ports */)) { | 962 if (!node_->CanShutdownCleanly(true /* allow_local_ports */)) { |
893 DVLOG(2) << "Unable to cleanly shut down node " << name_ << "."; | 963 DVLOG(2) << "Unable to cleanly shut down node " << name_ << "."; |
894 return; | 964 return; |
895 } | 965 } |
896 callback = shutdown_callback_; | 966 callback = shutdown_callback_; |
897 shutdown_callback_.Reset(); | 967 shutdown_callback_.Reset(); |
898 } | 968 } |
899 | 969 |
900 DCHECK(!callback.is_null()); | 970 DCHECK(!callback.is_null()); |
901 | 971 |
902 callback.Run(); | 972 callback.Run(); |
903 } | 973 } |
904 | 974 |
905 } // namespace edk | 975 } // namespace edk |
906 } // namespace mojo | 976 } // namespace mojo |
OLD | NEW |