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