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

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
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 the validation.
Mark Seaborn 2015/05/06 21:24:52 Nit: "for validation"? (no "the")
hidehiko 2015/05/07 01:29:06 Done.
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 434 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 void NaClProcessHost::OnResourcesReady() { 716 void NaClProcessHost::OnResourcesReady() {
651 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 717 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
652 if (!nacl_browser->IsReady()) { 718 if (!nacl_browser->IsReady()) {
653 SendErrorToRenderer("could not acquire shared resources needed by NaCl"); 719 SendErrorToRenderer("could not acquire shared resources needed by NaCl");
654 delete this; 720 delete this;
655 } else if (!StartNaClExecution()) { 721 } else if (!StartNaClExecution()) {
656 delete this; 722 delete this;
657 } 723 }
658 } 724 }
659 725
660 bool NaClProcessHost::ReplyToRenderer( 726 void NaClProcessHost::ReplyToRenderer(
661 const IPC::ChannelHandle& ppapi_channel_handle, 727 ScopedChannelHandle ppapi_channel_handle,
662 const IPC::ChannelHandle& trusted_channel_handle, 728 ScopedChannelHandle trusted_channel_handle,
663 const IPC::ChannelHandle& manifest_service_channel_handle) { 729 ScopedChannelHandle manifest_service_channel_handle) {
664 #if defined(OS_WIN) 730 #if defined(OS_WIN)
665 // If we are on 64-bit Windows, the NaCl process's sandbox is 731 // If we are on 64-bit Windows, the NaCl process's sandbox is
666 // managed by a different process from the renderer's sandbox. We 732 // managed by a different process from the renderer's sandbox. We
667 // need to inform the renderer's sandbox about the NaCl process so 733 // need to inform the renderer's sandbox about the NaCl process so
668 // that the renderer can send handles to the NaCl process using 734 // that the renderer can send handles to the NaCl process using
669 // BrokerDuplicateHandle(). 735 // BrokerDuplicateHandle().
670 if (RunningOnWOW64()) { 736 if (RunningOnWOW64()) {
671 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) { 737 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
672 SendErrorToRenderer("BrokerAddTargetPeer() failed"); 738 SendErrorToRenderer("BrokerAddTargetPeer() failed");
673 return false; 739 return;
674 } 740 }
675 } 741 }
676 #endif 742 #endif
677 743
678 FileDescriptor imc_handle_for_renderer; 744 // Hereafter, always we send an IPC message with handles which are not
Mark Seaborn 2015/05/06 21:24:52 Nit: "we always"
hidehiko 2015/05/07 01:29:06 Done.
679 #if defined(OS_WIN) 745 // closable in this process.
Mark Seaborn 2015/05/06 21:24:53 Nit: Clarify that the unclosability applies only t
hidehiko 2015/05/07 01:29:06 Done.
680 // Copy the handle into the renderer process. 746 IPC::PlatformFileForTransit imc_handle_for_renderer =
681 HANDLE handle_in_renderer; 747 IPC::TakeFileHandleForProcess(socket_for_renderer_.Pass(),
682 if (!DuplicateHandle(base::GetCurrentProcessHandle(), 748 nacl_host_message_filter_->PeerHandle());
683 socket_for_renderer_.TakePlatformFile(),
684 nacl_host_message_filter_->PeerHandle(),
685 &handle_in_renderer,
686 0, // Unused given DUPLICATE_SAME_ACCESS.
687 FALSE,
688 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
689 SendErrorToRenderer("DuplicateHandle() failed");
690 return false;
691 }
692 imc_handle_for_renderer = reinterpret_cast<FileDescriptor>(
693 handle_in_renderer);
694 #else
695 // No need to dup the imc_handle - we don't pass it anywhere else so
696 // it cannot be closed.
697 FileDescriptor imc_handle;
698 imc_handle.fd = socket_for_renderer_.TakePlatformFile();
699 imc_handle.auto_close = true;
700 imc_handle_for_renderer = imc_handle;
701 #endif
702 749
703 const ChildProcessData& data = process_->GetData(); 750 std::string error_message;
704 base::SharedMemoryHandle crash_info_shmem_renderer_handle; 751 base::SharedMemoryHandle crash_info_shmem_renderer_handle;
705 if (!crash_info_shmem_.ShareToProcess(nacl_host_message_filter_->PeerHandle(), 752 if (!crash_info_shmem_.ShareToProcess(nacl_host_message_filter_->PeerHandle(),
706 &crash_info_shmem_renderer_handle)) { 753 &crash_info_shmem_renderer_handle)) {
707 SendErrorToRenderer("ShareToProcess() failed"); 754 // On error, we do not send "IPC::ChannelHandle"s to the renderer process.
Mark Seaborn 2015/05/06 21:24:52 Can you also add: "Some other FDs/handles still g
hidehiko 2015/05/07 01:29:06 Done.
708 return false; 755 ppapi_channel_handle.reset();
756 trusted_channel_handle.reset();
757 manifest_service_channel_handle.reset();
758 error_message = "ShareToProcess() failed";
709 } 759 }
710 760
761 const ChildProcessData& data = process_->GetData();
Mark Seaborn 2015/05/06 21:24:52 Nit: if you're moving this, you could just use "pr
hidehiko 2015/05/07 01:29:06 Pls let me keep it as is. |data| is also used for
711 SendMessageToRenderer( 762 SendMessageToRenderer(
712 NaClLaunchResult(imc_handle_for_renderer, 763 NaClLaunchResult(imc_handle_for_renderer,
713 ppapi_channel_handle, 764 ppapi_channel_handle.release(),
714 trusted_channel_handle, 765 trusted_channel_handle.release(),
715 manifest_service_channel_handle, 766 manifest_service_channel_handle.release(),
716 base::GetProcId(data.handle), 767 base::GetProcId(data.handle),
717 data.id, 768 data.id,
718 crash_info_shmem_renderer_handle), 769 crash_info_shmem_renderer_handle),
719 std::string() /* error_message */); 770 error_message);
720 771
721 // Now that the crash information shmem handles have been shared with the 772 // Now that the crash information shmem handles have been shared with the
722 // plugin and the renderer, the browser can close its handle. 773 // plugin and the renderer, the browser can close its handle.
723 crash_info_shmem_.Close(); 774 crash_info_shmem_.Close();
724 return true;
725 } 775 }
726 776
727 void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) { 777 void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) {
728 LOG(ERROR) << "NaCl process launch failed: " << error_message; 778 LOG(ERROR) << "NaCl process launch failed: " << error_message;
729 SendMessageToRenderer(NaClLaunchResult(), error_message); 779 SendMessageToRenderer(NaClLaunchResult(), error_message);
730 } 780 }
731 781
732 void NaClProcessHost::SendMessageToRenderer( 782 void NaClProcessHost::SendMessageToRenderer(
733 const NaClLaunchResult& result, 783 const NaClLaunchResult& result,
734 const std::string& error_message) { 784 const std::string& error_message) {
735 DCHECK(nacl_host_message_filter_.get()); 785 DCHECK(nacl_host_message_filter_.get());
736 DCHECK(reply_msg_); 786 DCHECK(reply_msg_);
737 if (nacl_host_message_filter_.get() != NULL && reply_msg_ != NULL) { 787 if (nacl_host_message_filter_.get() == NULL || reply_msg_ == NULL) {
738 NaClHostMsg_LaunchNaCl::WriteReplyParams( 788 // As DCHECKed above, this case should not happen in general.
739 reply_msg_, result, error_message); 789 // Though, in the case, unfortunately there is no proper way to release
Mark Seaborn 2015/05/06 21:24:52 Nit: "in the case" -> "in this case"
hidehiko 2015/05/07 01:29:06 Done.
740 nacl_host_message_filter_->Send(reply_msg_); 790 // resources which are already created in |result|. We just give up to
Mark Seaborn 2015/05/06 21:24:52 Nit: "give up on releasing them"
hidehiko 2015/05/07 01:29:06 Done.
741 nacl_host_message_filter_ = NULL; 791 // release them, and leak them.
742 reply_msg_ = NULL; 792 return;
743 } 793 }
794
795 NaClHostMsg_LaunchNaCl::WriteReplyParams(reply_msg_, result, error_message);
796 nacl_host_message_filter_->Send(reply_msg_);
797 nacl_host_message_filter_ = NULL;
798 reply_msg_ = NULL;
744 } 799 }
745 800
746 void NaClProcessHost::SetDebugStubPort(int port) { 801 void NaClProcessHost::SetDebugStubPort(int port) {
747 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 802 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
748 nacl_browser->SetProcessGdbDebugStubPort(process_->GetData().id, port); 803 nacl_browser->SetProcessGdbDebugStubPort(process_->GetData().id, port);
749 } 804 }
750 805
751 #if defined(OS_POSIX) 806 #if defined(OS_POSIX)
752 // TCP port we chose for NaCl debug stub. It can be any other number. 807 // TCP port we chose for NaCl debug stub. It can be any other number.
753 static const uint16_t kInitialDebugStubPort = 4014; 808 static const uint16_t kInitialDebugStubPort = 4014;
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
932 } else { 987 } else {
933 params.nexe_file = IPC::TakeFileHandleForProcess( 988 params.nexe_file = IPC::TakeFileHandleForProcess(
934 nexe_file_.Pass(), process_->GetData().handle); 989 nexe_file_.Pass(), process_->GetData().handle);
935 } 990 }
936 process_->Send(new NaClProcessMsg_Start(params)); 991 process_->Send(new NaClProcessMsg_Start(params));
937 } 992 }
938 993
939 // This method is called when NaClProcessHostMsg_PpapiChannelCreated is 994 // This method is called when NaClProcessHostMsg_PpapiChannelCreated is
940 // received. 995 // received.
941 void NaClProcessHost::OnPpapiChannelsCreated( 996 void NaClProcessHost::OnPpapiChannelsCreated(
942 const IPC::ChannelHandle& browser_channel_handle, 997 const IPC::ChannelHandle& raw_browser_channel_handle,
943 const IPC::ChannelHandle& ppapi_renderer_channel_handle, 998 const IPC::ChannelHandle& raw_ppapi_renderer_channel_handle,
944 const IPC::ChannelHandle& trusted_renderer_channel_handle, 999 const IPC::ChannelHandle& raw_trusted_renderer_channel_handle,
945 const IPC::ChannelHandle& manifest_service_channel_handle) { 1000 const IPC::ChannelHandle& raw_manifest_service_channel_handle) {
1001 ScopedChannelHandle browser_channel_handle(raw_browser_channel_handle);
1002 ScopedChannelHandle ppapi_renderer_channel_handle(
1003 raw_ppapi_renderer_channel_handle);
1004 ScopedChannelHandle trusted_renderer_channel_handle(
1005 raw_trusted_renderer_channel_handle);
1006 ScopedChannelHandle manifest_service_channel_handle(
1007 raw_manifest_service_channel_handle);
1008
946 if (!enable_ppapi_proxy()) { 1009 if (!enable_ppapi_proxy()) {
947 ReplyToRenderer(IPC::ChannelHandle(), 1010 ReplyToRenderer(ScopedChannelHandle(),
948 trusted_renderer_channel_handle, 1011 trusted_renderer_channel_handle.Pass(),
949 manifest_service_channel_handle); 1012 manifest_service_channel_handle.Pass());
950 return; 1013 return;
951 } 1014 }
952 1015
953 if (!ipc_proxy_channel_.get()) { 1016 if (ipc_proxy_channel_.get()) {
954 DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type);
955
956 ipc_proxy_channel_ =
957 IPC::ChannelProxy::Create(browser_channel_handle,
958 IPC::Channel::MODE_CLIENT,
959 NULL,
960 base::MessageLoopProxy::current().get());
961 // Create the browser ppapi host and enable PPAPI message dispatching to the
962 // browser process.
963 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
964 ipc_proxy_channel_.get(), // sender
965 permissions_,
966 process_->GetData().handle,
967 ipc_proxy_channel_.get(),
968 nacl_host_message_filter_->render_process_id(),
969 render_view_id_,
970 profile_directory_));
971 ppapi_host_->SetOnKeepaliveCallback(
972 NaClBrowser::GetDelegate()->GetOnKeepaliveCallback());
973
974 ppapi::PpapiNaClPluginArgs args;
975 args.off_the_record = nacl_host_message_filter_->off_the_record();
976 args.permissions = permissions_;
977 args.keepalive_throttle_interval_milliseconds =
978 keepalive_throttle_interval_milliseconds_;
979 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
980 DCHECK(cmdline);
981 std::string flag_whitelist[] = {
982 switches::kV,
983 switches::kVModule,
984 };
985 for (size_t i = 0; i < arraysize(flag_whitelist); ++i) {
986 std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]);
987 if (!value.empty()) {
988 args.switch_names.push_back(flag_whitelist[i]);
989 args.switch_values.push_back(value);
990 }
991 }
992
993 ppapi_host_->GetPpapiHost()->AddHostFactoryFilter(
994 scoped_ptr<ppapi::host::HostFactory>(
995 NaClBrowser::GetDelegate()->CreatePpapiHostFactory(
996 ppapi_host_.get())));
997
998 // Send a message to initialize the IPC dispatchers in the NaCl plugin.
999 ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args));
1000
1001 // Let the renderer know that the IPC channels are established.
1002 ReplyToRenderer(ppapi_renderer_channel_handle,
1003 trusted_renderer_channel_handle,
1004 manifest_service_channel_handle);
1005 } else {
1006 // Attempt to open more than 1 browser channel is not supported. 1017 // Attempt to open more than 1 browser channel is not supported.
1007 // Shut down the NaCl process. 1018 // Shut down the NaCl process.
1008 process_->GetHost()->ForceShutdown(); 1019 process_->GetHost()->ForceShutdown();
1020 return;
1009 } 1021 }
1022
1023 DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type);
1024
1025 ipc_proxy_channel_ =
1026 IPC::ChannelProxy::Create(browser_channel_handle.release(),
1027 IPC::Channel::MODE_CLIENT,
1028 NULL,
1029 base::MessageLoopProxy::current().get());
1030 // Create the browser ppapi host and enable PPAPI message dispatching to the
1031 // browser process.
1032 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
1033 ipc_proxy_channel_.get(), // sender
1034 permissions_,
1035 process_->GetData().handle,
1036 ipc_proxy_channel_.get(),
1037 nacl_host_message_filter_->render_process_id(),
1038 render_view_id_,
1039 profile_directory_));
1040 ppapi_host_->SetOnKeepaliveCallback(
1041 NaClBrowser::GetDelegate()->GetOnKeepaliveCallback());
1042
1043 ppapi::PpapiNaClPluginArgs args;
1044 args.off_the_record = nacl_host_message_filter_->off_the_record();
1045 args.permissions = permissions_;
1046 args.keepalive_throttle_interval_milliseconds =
1047 keepalive_throttle_interval_milliseconds_;
1048 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1049 DCHECK(cmdline);
1050 std::string flag_whitelist[] = {
1051 switches::kV,
1052 switches::kVModule,
1053 };
1054 for (size_t i = 0; i < arraysize(flag_whitelist); ++i) {
1055 std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]);
1056 if (!value.empty()) {
1057 args.switch_names.push_back(flag_whitelist[i]);
1058 args.switch_values.push_back(value);
1059 }
1060 }
1061
1062 ppapi_host_->GetPpapiHost()->AddHostFactoryFilter(
1063 scoped_ptr<ppapi::host::HostFactory>(
1064 NaClBrowser::GetDelegate()->CreatePpapiHostFactory(
1065 ppapi_host_.get())));
1066
1067 // Send a message to initialize the IPC dispatchers in the NaCl plugin.
1068 ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args));
1069
1070 // Let the renderer know that the IPC channels are established.
1071 ReplyToRenderer(ppapi_renderer_channel_handle.Pass(),
1072 trusted_renderer_channel_handle.Pass(),
1073 manifest_service_channel_handle.Pass());
1010 } 1074 }
1011 1075
1012 bool NaClProcessHost::StartWithLaunchedProcess() { 1076 bool NaClProcessHost::StartWithLaunchedProcess() {
1013 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 1077 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
1014 1078
1015 if (nacl_browser->IsReady()) { 1079 if (nacl_browser->IsReady()) {
1016 return StartNaClExecution(); 1080 return StartNaClExecution();
1017 } else if (nacl_browser->IsOk()) { 1081 } else if (nacl_browser->IsOk()) {
1018 nacl_browser->WaitForResources( 1082 nacl_browser->WaitForResources(
1019 base::Bind(&NaClProcessHost::OnResourcesReady, 1083 base::Bind(&NaClProcessHost::OnResourcesReady,
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1180 process.Pass(), info, 1244 process.Pass(), info,
1181 base::MessageLoopProxy::current(), 1245 base::MessageLoopProxy::current(),
1182 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker, 1246 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker,
1183 weak_factory_.GetWeakPtr())); 1247 weak_factory_.GetWeakPtr()));
1184 return true; 1248 return true;
1185 } 1249 }
1186 } 1250 }
1187 #endif 1251 #endif
1188 1252
1189 } // namespace nacl 1253 } // namespace nacl
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698