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