Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(228)

Side by Side Diff: components/nacl/browser/nacl_process_host.cc

Issue 1094653003: Refactor NaClProcessHost. Reduce chances to leak the resource. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/nacl/browser/nacl_process_host.h ('k') | components/nacl/common/nacl_types.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "components/nacl/browser/nacl_process_host.h" 5 #include "components/nacl/browser/nacl_process_host.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 196
197 void CloseFile(base::File file) { 197 void CloseFile(base::File file) {
198 // The base::File destructor will close the file for us. 198 // The base::File destructor will close the file for us.
199 } 199 }
200 200
201 } // namespace 201 } // namespace
202 202
203 unsigned NaClProcessHost::keepalive_throttle_interval_milliseconds_ = 203 unsigned NaClProcessHost::keepalive_throttle_interval_milliseconds_ =
204 ppapi::kKeepaliveThrottleIntervalDefaultMilliseconds; 204 ppapi::kKeepaliveThrottleIntervalDefaultMilliseconds;
205 205
206 // Unfortunately, we cannot use ScopedGeneric directly for IPC::ChannelHandle,
207 // because there is neither operator== nor operator != definition for it.
208 // Instead, define a simple wrapper for IPC::ChannelHandle with an assumption
209 // that this only takes a transferred IPC::ChannelHandle or one to be
210 // transferred via IPC.
211 class NaClProcessHost::ScopedChannelHandle {
212 MOVE_ONLY_TYPE_FOR_CPP_03(ScopedChannelHandle, RValue);
213 public:
214 ScopedChannelHandle() {
215 }
216 explicit ScopedChannelHandle(const IPC::ChannelHandle& handle)
217 : handle_(handle) {
218 DCHECK(IsSupportedHandle(handle_));
219 }
220 ScopedChannelHandle(RValue other) : handle_(other.object->handle_) {
221 other.object->handle_ = IPC::ChannelHandle();
222 DCHECK(IsSupportedHandle(handle_));
223 }
224 ~ScopedChannelHandle() {
225 CloseIfNecessary();
226 }
227
228 const IPC::ChannelHandle& get() const { return handle_; }
229 IPC::ChannelHandle release() WARN_UNUSED_RESULT {
230 IPC::ChannelHandle result = handle_;
231 handle_ = IPC::ChannelHandle();
232 return result;
233 }
234
235 void reset(const IPC::ChannelHandle& handle = IPC::ChannelHandle()) {
236 DCHECK(IsSupportedHandle(handle));
237 #if defined(OS_POSIX)
238 // Following the manner of base::ScopedGeneric, we do not support
239 // reset() with same handle for simplicity of the implementation.
240 CHECK(handle.socket.fd == -1 || handle.socket.fd != handle_.socket.fd);
241 #endif
242 CloseIfNecessary();
243 handle_ = handle;
244 }
245
246 private:
247 // Returns true if the given handle is closable automatically by this
248 // class. This function is just a helper for validation.
249 static bool IsSupportedHandle(const IPC::ChannelHandle& handle) {
250 #if defined(OS_WIN)
251 // On Windows, it is not supported to marshal the |pipe.handle|.
252 // In our case, we wrap a transferred ChannelHandle (or one to be
253 // transferred) via IPC, so we can assume |handle.pipe.handle| is NULL.
254 return handle.pipe.handle == NULL;
255 #else
256 return true;
257 #endif
258 }
259
260 void CloseIfNecessary() {
261 #if defined(OS_POSIX)
262 if (handle_.socket.auto_close) {
263 // Defer closing task to the ScopedFD.
264 base::ScopedFD(handle_.socket.fd);
265 }
266 #endif
267 }
268
269 IPC::ChannelHandle handle_;
270 };
271
206 NaClProcessHost::NaClProcessHost( 272 NaClProcessHost::NaClProcessHost(
207 const GURL& manifest_url, 273 const GURL& manifest_url,
208 base::File nexe_file, 274 base::File nexe_file,
209 const NaClFileToken& nexe_token, 275 const NaClFileToken& nexe_token,
210 const std::vector<NaClResourcePrefetchResult>& prefetched_resource_files, 276 const std::vector<NaClResourcePrefetchResult>& prefetched_resource_files,
211 ppapi::PpapiPermissions permissions, 277 ppapi::PpapiPermissions permissions,
212 int render_view_id, 278 int render_view_id,
213 uint32 permission_bits, 279 uint32 permission_bits,
214 bool uses_nonsfi_mode, 280 bool uses_nonsfi_mode,
215 bool off_the_record, 281 bool off_the_record,
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
649 void NaClProcessHost::OnResourcesReady() { 715 void NaClProcessHost::OnResourcesReady() {
650 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 716 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
651 if (!nacl_browser->IsReady()) { 717 if (!nacl_browser->IsReady()) {
652 SendErrorToRenderer("could not acquire shared resources needed by NaCl"); 718 SendErrorToRenderer("could not acquire shared resources needed by NaCl");
653 delete this; 719 delete this;
654 } else if (!StartNaClExecution()) { 720 } else if (!StartNaClExecution()) {
655 delete this; 721 delete this;
656 } 722 }
657 } 723 }
658 724
659 bool NaClProcessHost::ReplyToRenderer( 725 void NaClProcessHost::ReplyToRenderer(
660 const IPC::ChannelHandle& ppapi_channel_handle, 726 ScopedChannelHandle ppapi_channel_handle,
661 const IPC::ChannelHandle& trusted_channel_handle, 727 ScopedChannelHandle trusted_channel_handle,
662 const IPC::ChannelHandle& manifest_service_channel_handle) { 728 ScopedChannelHandle manifest_service_channel_handle) {
663 #if defined(OS_WIN) 729 #if defined(OS_WIN)
664 // If we are on 64-bit Windows, the NaCl process's sandbox is 730 // If we are on 64-bit Windows, the NaCl process's sandbox is
665 // managed by a different process from the renderer's sandbox. We 731 // managed by a different process from the renderer's sandbox. We
666 // need to inform the renderer's sandbox about the NaCl process so 732 // need to inform the renderer's sandbox about the NaCl process so
667 // that the renderer can send handles to the NaCl process using 733 // that the renderer can send handles to the NaCl process using
668 // BrokerDuplicateHandle(). 734 // BrokerDuplicateHandle().
669 if (RunningOnWOW64()) { 735 if (RunningOnWOW64()) {
670 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) { 736 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
671 SendErrorToRenderer("BrokerAddTargetPeer() failed"); 737 SendErrorToRenderer("BrokerAddTargetPeer() failed");
672 return false; 738 return;
673 } 739 }
674 } 740 }
675 #endif 741 #endif
676 742
677 FileDescriptor imc_handle_for_renderer; 743 // Hereafter, we always send an IPC message with handles which, on Windows,
678 #if defined(OS_WIN) 744 // are not closable in this process.
679 // Copy the handle into the renderer process. 745 IPC::PlatformFileForTransit imc_handle_for_renderer =
680 HANDLE handle_in_renderer; 746 IPC::TakeFileHandleForProcess(socket_for_renderer_.Pass(),
Mark Seaborn 2015/05/07 22:19:56 Looking again, I noticed that you're not checking
hidehiko 2015/05/11 12:08:35 Ah, you're right. I'll send another CL.
681 if (!DuplicateHandle(base::GetCurrentProcessHandle(), 747 nacl_host_message_filter_->PeerHandle());
682 socket_for_renderer_.TakePlatformFile(),
683 nacl_host_message_filter_->PeerHandle(),
684 &handle_in_renderer,
685 0, // Unused given DUPLICATE_SAME_ACCESS.
686 FALSE,
687 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
688 SendErrorToRenderer("DuplicateHandle() failed");
689 return false;
690 }
691 imc_handle_for_renderer = reinterpret_cast<FileDescriptor>(
692 handle_in_renderer);
693 #else
694 // No need to dup the imc_handle - we don't pass it anywhere else so
695 // it cannot be closed.
696 FileDescriptor imc_handle;
697 imc_handle.fd = socket_for_renderer_.TakePlatformFile();
698 imc_handle.auto_close = true;
699 imc_handle_for_renderer = imc_handle;
700 #endif
701 748
702 const ChildProcessData& data = process_->GetData(); 749 std::string error_message;
703 base::SharedMemoryHandle crash_info_shmem_renderer_handle; 750 base::SharedMemoryHandle crash_info_shmem_renderer_handle;
704 if (!crash_info_shmem_.ShareToProcess(nacl_host_message_filter_->PeerHandle(), 751 if (!crash_info_shmem_.ShareToProcess(nacl_host_message_filter_->PeerHandle(),
705 &crash_info_shmem_renderer_handle)) { 752 &crash_info_shmem_renderer_handle)) {
706 SendErrorToRenderer("ShareToProcess() failed"); 753 // On error, we do not send "IPC::ChannelHandle"s to the renderer process.
707 return false; 754 // Note that some other FDs/handles still get sent to the renderer, but
755 // will be closed there.
756 ppapi_channel_handle.reset();
757 trusted_channel_handle.reset();
758 manifest_service_channel_handle.reset();
759 error_message = "ShareToProcess() failed";
708 } 760 }
709 761
762 const ChildProcessData& data = process_->GetData();
710 SendMessageToRenderer( 763 SendMessageToRenderer(
711 NaClLaunchResult(imc_handle_for_renderer, 764 NaClLaunchResult(imc_handle_for_renderer,
712 ppapi_channel_handle, 765 ppapi_channel_handle.release(),
713 trusted_channel_handle, 766 trusted_channel_handle.release(),
714 manifest_service_channel_handle, 767 manifest_service_channel_handle.release(),
715 base::GetProcId(data.handle), 768 base::GetProcId(data.handle),
716 data.id, 769 data.id,
717 crash_info_shmem_renderer_handle), 770 crash_info_shmem_renderer_handle),
718 std::string() /* error_message */); 771 error_message);
719 772
720 // Now that the crash information shmem handles have been shared with the 773 // Now that the crash information shmem handles have been shared with the
721 // plugin and the renderer, the browser can close its handle. 774 // plugin and the renderer, the browser can close its handle.
722 crash_info_shmem_.Close(); 775 crash_info_shmem_.Close();
723 return true;
724 } 776 }
725 777
726 void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) { 778 void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) {
727 LOG(ERROR) << "NaCl process launch failed: " << error_message; 779 LOG(ERROR) << "NaCl process launch failed: " << error_message;
728 SendMessageToRenderer(NaClLaunchResult(), error_message); 780 SendMessageToRenderer(NaClLaunchResult(), error_message);
729 } 781 }
730 782
731 void NaClProcessHost::SendMessageToRenderer( 783 void NaClProcessHost::SendMessageToRenderer(
732 const NaClLaunchResult& result, 784 const NaClLaunchResult& result,
733 const std::string& error_message) { 785 const std::string& error_message) {
734 DCHECK(nacl_host_message_filter_.get()); 786 DCHECK(nacl_host_message_filter_.get());
735 DCHECK(reply_msg_); 787 DCHECK(reply_msg_);
736 if (nacl_host_message_filter_.get() != NULL && reply_msg_ != NULL) { 788 if (nacl_host_message_filter_.get() == NULL || reply_msg_ == NULL) {
737 NaClHostMsg_LaunchNaCl::WriteReplyParams( 789 // As DCHECKed above, this case should not happen in general.
738 reply_msg_, result, error_message); 790 // Though, in this case, unfortunately there is no proper way to release
739 nacl_host_message_filter_->Send(reply_msg_); 791 // resources which are already created in |result|. We just give up on
740 nacl_host_message_filter_ = NULL; 792 // releasing them, and leak them.
741 reply_msg_ = NULL; 793 return;
742 } 794 }
795
796 NaClHostMsg_LaunchNaCl::WriteReplyParams(reply_msg_, result, error_message);
797 nacl_host_message_filter_->Send(reply_msg_);
798 nacl_host_message_filter_ = NULL;
799 reply_msg_ = NULL;
743 } 800 }
744 801
745 void NaClProcessHost::SetDebugStubPort(int port) { 802 void NaClProcessHost::SetDebugStubPort(int port) {
746 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 803 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
747 nacl_browser->SetProcessGdbDebugStubPort(process_->GetData().id, port); 804 nacl_browser->SetProcessGdbDebugStubPort(process_->GetData().id, port);
748 } 805 }
749 806
750 #if defined(OS_POSIX) 807 #if defined(OS_POSIX)
751 // TCP port we chose for NaCl debug stub. It can be any other number. 808 // TCP port we chose for NaCl debug stub. It can be any other number.
752 static const uint16_t kInitialDebugStubPort = 4014; 809 static const uint16_t kInitialDebugStubPort = 4014;
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
934 } else { 991 } else {
935 params.nexe_file = IPC::TakeFileHandleForProcess( 992 params.nexe_file = IPC::TakeFileHandleForProcess(
936 nexe_file_.Pass(), process_->GetData().handle); 993 nexe_file_.Pass(), process_->GetData().handle);
937 } 994 }
938 process_->Send(new NaClProcessMsg_Start(params)); 995 process_->Send(new NaClProcessMsg_Start(params));
939 } 996 }
940 997
941 // This method is called when NaClProcessHostMsg_PpapiChannelCreated is 998 // This method is called when NaClProcessHostMsg_PpapiChannelCreated is
942 // received. 999 // received.
943 void NaClProcessHost::OnPpapiChannelsCreated( 1000 void NaClProcessHost::OnPpapiChannelsCreated(
944 const IPC::ChannelHandle& browser_channel_handle, 1001 const IPC::ChannelHandle& raw_browser_channel_handle,
945 const IPC::ChannelHandle& ppapi_renderer_channel_handle, 1002 const IPC::ChannelHandle& raw_ppapi_renderer_channel_handle,
946 const IPC::ChannelHandle& trusted_renderer_channel_handle, 1003 const IPC::ChannelHandle& raw_trusted_renderer_channel_handle,
947 const IPC::ChannelHandle& manifest_service_channel_handle) { 1004 const IPC::ChannelHandle& raw_manifest_service_channel_handle) {
1005 ScopedChannelHandle browser_channel_handle(raw_browser_channel_handle);
1006 ScopedChannelHandle ppapi_renderer_channel_handle(
1007 raw_ppapi_renderer_channel_handle);
1008 ScopedChannelHandle trusted_renderer_channel_handle(
1009 raw_trusted_renderer_channel_handle);
1010 ScopedChannelHandle manifest_service_channel_handle(
1011 raw_manifest_service_channel_handle);
1012
948 if (!enable_ppapi_proxy()) { 1013 if (!enable_ppapi_proxy()) {
949 ReplyToRenderer(IPC::ChannelHandle(), 1014 ReplyToRenderer(ScopedChannelHandle(),
950 trusted_renderer_channel_handle, 1015 trusted_renderer_channel_handle.Pass(),
951 manifest_service_channel_handle); 1016 manifest_service_channel_handle.Pass());
952 return; 1017 return;
953 } 1018 }
954 1019
955 if (!ipc_proxy_channel_.get()) { 1020 if (ipc_proxy_channel_.get()) {
956 DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type);
957
958 ipc_proxy_channel_ =
959 IPC::ChannelProxy::Create(browser_channel_handle,
960 IPC::Channel::MODE_CLIENT,
961 NULL,
962 base::MessageLoopProxy::current().get());
963 // Create the browser ppapi host and enable PPAPI message dispatching to the
964 // browser process.
965 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
966 ipc_proxy_channel_.get(), // sender
967 permissions_,
968 process_->GetData().handle,
969 ipc_proxy_channel_.get(),
970 nacl_host_message_filter_->render_process_id(),
971 render_view_id_,
972 profile_directory_));
973 ppapi_host_->SetOnKeepaliveCallback(
974 NaClBrowser::GetDelegate()->GetOnKeepaliveCallback());
975
976 ppapi::PpapiNaClPluginArgs args;
977 args.off_the_record = nacl_host_message_filter_->off_the_record();
978 args.permissions = permissions_;
979 args.keepalive_throttle_interval_milliseconds =
980 keepalive_throttle_interval_milliseconds_;
981 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
982 DCHECK(cmdline);
983 std::string flag_whitelist[] = {
984 switches::kV,
985 switches::kVModule,
986 };
987 for (size_t i = 0; i < arraysize(flag_whitelist); ++i) {
988 std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]);
989 if (!value.empty()) {
990 args.switch_names.push_back(flag_whitelist[i]);
991 args.switch_values.push_back(value);
992 }
993 }
994
995 ppapi_host_->GetPpapiHost()->AddHostFactoryFilter(
996 scoped_ptr<ppapi::host::HostFactory>(
997 NaClBrowser::GetDelegate()->CreatePpapiHostFactory(
998 ppapi_host_.get())));
999
1000 // Send a message to initialize the IPC dispatchers in the NaCl plugin.
1001 ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args));
1002
1003 // Let the renderer know that the IPC channels are established.
1004 ReplyToRenderer(ppapi_renderer_channel_handle,
1005 trusted_renderer_channel_handle,
1006 manifest_service_channel_handle);
1007 } else {
1008 // Attempt to open more than 1 browser channel is not supported. 1021 // Attempt to open more than 1 browser channel is not supported.
1009 // Shut down the NaCl process. 1022 // Shut down the NaCl process.
1010 process_->GetHost()->ForceShutdown(); 1023 process_->GetHost()->ForceShutdown();
1024 return;
1011 } 1025 }
1026
1027 DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type);
1028
1029 ipc_proxy_channel_ =
1030 IPC::ChannelProxy::Create(browser_channel_handle.release(),
1031 IPC::Channel::MODE_CLIENT,
1032 NULL,
1033 base::MessageLoopProxy::current().get());
1034 // Create the browser ppapi host and enable PPAPI message dispatching to the
1035 // browser process.
1036 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
1037 ipc_proxy_channel_.get(), // sender
1038 permissions_,
1039 process_->GetData().handle,
1040 ipc_proxy_channel_.get(),
1041 nacl_host_message_filter_->render_process_id(),
1042 render_view_id_,
1043 profile_directory_));
1044 ppapi_host_->SetOnKeepaliveCallback(
1045 NaClBrowser::GetDelegate()->GetOnKeepaliveCallback());
1046
1047 ppapi::PpapiNaClPluginArgs args;
1048 args.off_the_record = nacl_host_message_filter_->off_the_record();
1049 args.permissions = permissions_;
1050 args.keepalive_throttle_interval_milliseconds =
1051 keepalive_throttle_interval_milliseconds_;
1052 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1053 DCHECK(cmdline);
1054 std::string flag_whitelist[] = {
1055 switches::kV,
1056 switches::kVModule,
1057 };
1058 for (size_t i = 0; i < arraysize(flag_whitelist); ++i) {
1059 std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]);
1060 if (!value.empty()) {
1061 args.switch_names.push_back(flag_whitelist[i]);
1062 args.switch_values.push_back(value);
1063 }
1064 }
1065
1066 ppapi_host_->GetPpapiHost()->AddHostFactoryFilter(
1067 scoped_ptr<ppapi::host::HostFactory>(
1068 NaClBrowser::GetDelegate()->CreatePpapiHostFactory(
1069 ppapi_host_.get())));
1070
1071 // Send a message to initialize the IPC dispatchers in the NaCl plugin.
1072 ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args));
1073
1074 // Let the renderer know that the IPC channels are established.
1075 ReplyToRenderer(ppapi_renderer_channel_handle.Pass(),
1076 trusted_renderer_channel_handle.Pass(),
1077 manifest_service_channel_handle.Pass());
1012 } 1078 }
1013 1079
1014 bool NaClProcessHost::StartWithLaunchedProcess() { 1080 bool NaClProcessHost::StartWithLaunchedProcess() {
1015 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 1081 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
1016 1082
1017 if (nacl_browser->IsReady()) { 1083 if (nacl_browser->IsReady()) {
1018 return StartNaClExecution(); 1084 return StartNaClExecution();
1019 } else if (nacl_browser->IsOk()) { 1085 } else if (nacl_browser->IsOk()) {
1020 nacl_browser->WaitForResources( 1086 nacl_browser->WaitForResources(
1021 base::Bind(&NaClProcessHost::OnResourcesReady, 1087 base::Bind(&NaClProcessHost::OnResourcesReady,
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1182 process.Pass(), info, 1248 process.Pass(), info,
1183 base::MessageLoopProxy::current(), 1249 base::MessageLoopProxy::current(),
1184 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker, 1250 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker,
1185 weak_factory_.GetWeakPtr())); 1251 weak_factory_.GetWeakPtr()));
1186 return true; 1252 return true;
1187 } 1253 }
1188 } 1254 }
1189 #endif 1255 #endif
1190 1256
1191 } // namespace nacl 1257 } // namespace nacl
OLDNEW
« no previous file with comments | « components/nacl/browser/nacl_process_host.h ('k') | components/nacl/common/nacl_types.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698