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

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, 8 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
11 #include "base/base_switches.h" 11 #include "base/base_switches.h"
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/command_line.h" 13 #include "base/command_line.h"
14 #include "base/files/file_util.h" 14 #include "base/files/file_util.h"
15 #include "base/message_loop/message_loop.h" 15 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/histogram.h" 16 #include "base/metrics/histogram.h"
17 #include "base/move.h"
17 #include "base/path_service.h" 18 #include "base/path_service.h"
18 #include "base/process/launch.h" 19 #include "base/process/launch.h"
19 #include "base/process/process_iterator.h" 20 #include "base/process/process_iterator.h"
20 #include "base/rand_util.h" 21 #include "base/rand_util.h"
22 #include "base/scoped_generic.h"
21 #include "base/strings/string_number_conversions.h" 23 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_split.h" 24 #include "base/strings/string_split.h"
23 #include "base/strings/string_util.h" 25 #include "base/strings/string_util.h"
24 #include "base/strings/stringprintf.h" 26 #include "base/strings/stringprintf.h"
25 #include "base/strings/utf_string_conversions.h" 27 #include "base/strings/utf_string_conversions.h"
26 #include "base/threading/sequenced_worker_pool.h" 28 #include "base/threading/sequenced_worker_pool.h"
27 #include "base/win/windows_version.h" 29 #include "base/win/windows_version.h"
28 #include "build/build_config.h" 30 #include "build/build_config.h"
29 #include "components/nacl/browser/nacl_browser.h" 31 #include "components/nacl/browser/nacl_browser.h"
30 #include "components/nacl/browser/nacl_browser_delegate.h" 32 #include "components/nacl/browser/nacl_browser_delegate.h"
31 #include "components/nacl/browser/nacl_host_message_filter.h" 33 #include "components/nacl/browser/nacl_host_message_filter.h"
32 #include "components/nacl/common/nacl_cmd_line.h" 34 #include "components/nacl/common/nacl_cmd_line.h"
33 #include "components/nacl/common/nacl_host_messages.h" 35 #include "components/nacl/common/nacl_host_messages.h"
34 #include "components/nacl/common/nacl_messages.h" 36 #include "components/nacl/common/nacl_messages.h"
35 #include "components/nacl/common/nacl_process_type.h" 37 #include "components/nacl/common/nacl_process_type.h"
36 #include "components/nacl/common/nacl_switches.h" 38 #include "components/nacl/common/nacl_switches.h"
37 #include "content/public/browser/browser_child_process_host.h" 39 #include "content/public/browser/browser_child_process_host.h"
38 #include "content/public/browser/browser_ppapi_host.h" 40 #include "content/public/browser/browser_ppapi_host.h"
39 #include "content/public/browser/child_process_data.h" 41 #include "content/public/browser/child_process_data.h"
40 #include "content/public/browser/plugin_service.h" 42 #include "content/public/browser/plugin_service.h"
41 #include "content/public/browser/render_process_host.h" 43 #include "content/public/browser/render_process_host.h"
42 #include "content/public/browser/web_contents.h" 44 #include "content/public/browser/web_contents.h"
43 #include "content/public/common/child_process_host.h" 45 #include "content/public/common/child_process_host.h"
44 #include "content/public/common/content_switches.h" 46 #include "content/public/common/content_switches.h"
45 #include "content/public/common/process_type.h" 47 #include "content/public/common/process_type.h"
46 #include "content/public/common/sandboxed_process_launcher_delegate.h" 48 #include "content/public/common/sandboxed_process_launcher_delegate.h"
47 #include "ipc/ipc_channel.h" 49 #include "ipc/ipc_channel.h"
50 #include "ipc/ipc_channel_handle.h"
51 #include "ipc/ipc_platform_file.h"
48 #include "ipc/ipc_switches.h" 52 #include "ipc/ipc_switches.h"
49 #include "native_client/src/shared/imc/nacl_imc_c.h" 53 #include "native_client/src/shared/imc/nacl_imc_c.h"
50 #include "net/base/net_util.h" 54 #include "net/base/net_util.h"
51 #include "net/socket/tcp_listen_socket.h" 55 #include "net/socket/tcp_listen_socket.h"
52 #include "ppapi/host/host_factory.h" 56 #include "ppapi/host/host_factory.h"
53 #include "ppapi/host/ppapi_host.h" 57 #include "ppapi/host/ppapi_host.h"
54 #include "ppapi/proxy/ppapi_messages.h" 58 #include "ppapi/proxy/ppapi_messages.h"
55 #include "ppapi/shared_impl/ppapi_constants.h" 59 #include "ppapi/shared_impl/ppapi_constants.h"
56 #include "ppapi/shared_impl/ppapi_nacl_plugin_args.h" 60 #include "ppapi/shared_impl/ppapi_nacl_plugin_args.h"
57 61
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 return (base::win::OSInfo::GetInstance()->wow64_status() == 146 return (base::win::OSInfo::GetInstance()->wow64_status() ==
143 base::win::OSInfo::WOW64_ENABLED); 147 base::win::OSInfo::WOW64_ENABLED);
144 } 148 }
145 149
146 } // namespace 150 } // namespace
147 151
148 #endif // defined(OS_WIN) 152 #endif // defined(OS_WIN)
149 153
150 namespace { 154 namespace {
151 155
156 // Usually, NaClProcessHost is working on IO thread, where file operation is
Mark Seaborn 2015/04/17 22:13:45 As an aside: I am sceptical that close() or CloseH
hidehiko 2015/04/30 16:33:01 According to my coworker who is the expert of Wind
157 // not allowed. So, even just for closing the file, it is necessary to post
158 // the task to blocking pool. Note that, it is safer to use this from
159 // NaClProcessHost's destructor runnign on IO thread, because BlockingPool
Mark Seaborn 2015/04/17 22:13:45 "running"
hidehiko 2015/04/30 16:33:02 Acknowledged.
160 // is ensured to be alive while the IO thread is alive.
161 void CloseFile(base::File file) {
Mark Seaborn 2015/04/17 22:13:45 CloseFile() is a rather generic name. Maybe Close
hidehiko 2015/04/30 16:33:01 Then, probably PostCloseFile etc. would be better.
162 if (!file.IsValid()) {
163 return;
164 }
165
166 content::BrowserThread::GetBlockingPool()->PostTask(
167 FROM_HERE,
168 base::Bind(&(ignore_result<base::File>), base::Passed(&file)));
Mark Seaborn 2015/04/17 22:13:45 Nit: is it possible to omit the ()s in "&(ignore_r
hidehiko 2015/04/30 16:33:02 Reflected in another CL. I just misunderstood it m
169 }
170
171 // Define "Scoped" handles as utilities to avoid resource leaks.
172 struct PlatformFileForTransitTraits {
173 static IPC::PlatformFileForTransit InvalidValue() {
174 return IPC::InvalidPlatformFileForTransit();
175 }
176
177 static void Free(const IPC::PlatformFileForTransit& file) {
178 CloseFile(IPC::PlatformFileForTransitToFile(file).Pass());
Mark Seaborn 2015/04/17 22:13:45 I think this is unsafe on Windows, because this is
hidehiko 2015/04/30 16:33:01 You're right. Fixed.
179 }
180 };
181
182 typedef base::ScopedGeneric<
183 IPC::PlatformFileForTransit, PlatformFileForTransitTraits>
184 ScopedPlatformFileForTransit;
185
186 struct SharedMemoryHandleTraits {
187 static base::SharedMemoryHandle InvalidValue() {
188 return base::SharedMemory::NULLHandle();
189 }
190
191 static void Free(const base::SharedMemoryHandle& handle) {
192 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
193 base::SharedMemory::CloseHandle(handle);
194 }
195 };
196
197 typedef base::ScopedGeneric<
198 base::SharedMemoryHandle, SharedMemoryHandleTraits>
199 ScopedSharedMemoryHandle;
200
152 // NOTE: changes to this class need to be reviewed by the security team. 201 // NOTE: changes to this class need to be reviewed by the security team.
153 class NaClSandboxedProcessLauncherDelegate 202 class NaClSandboxedProcessLauncherDelegate
154 : public content::SandboxedProcessLauncherDelegate { 203 : public content::SandboxedProcessLauncherDelegate {
155 public: 204 public:
156 NaClSandboxedProcessLauncherDelegate(ChildProcessHost* host) 205 NaClSandboxedProcessLauncherDelegate(ChildProcessHost* host)
157 #if defined(OS_POSIX) 206 #if defined(OS_POSIX)
158 : ipc_fd_(host->TakeClientFileDescriptor()) 207 : ipc_fd_(host->TakeClientFileDescriptor())
159 #endif 208 #endif
160 {} 209 {}
161 210
(...skipping 25 matching lines...) Expand all
187 236
188 void SetCloseOnExec(NaClHandle fd) { 237 void SetCloseOnExec(NaClHandle fd) {
189 #if defined(OS_POSIX) 238 #if defined(OS_POSIX)
190 int flags = fcntl(fd, F_GETFD); 239 int flags = fcntl(fd, F_GETFD);
191 CHECK_NE(flags, -1); 240 CHECK_NE(flags, -1);
192 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 241 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
193 CHECK_EQ(rc, 0); 242 CHECK_EQ(rc, 0);
194 #endif 243 #endif
195 } 244 }
196 245
197 bool ShareHandleToSelLdr(
198 base::ProcessHandle processh,
199 NaClHandle sourceh,
200 bool close_source,
201 std::vector<nacl::FileDescriptor> *handles_for_sel_ldr) {
202 #if defined(OS_WIN)
203 HANDLE channel;
204 int flags = DUPLICATE_SAME_ACCESS;
205 if (close_source)
206 flags |= DUPLICATE_CLOSE_SOURCE;
207 if (!DuplicateHandle(GetCurrentProcess(),
208 reinterpret_cast<HANDLE>(sourceh),
209 processh,
210 &channel,
211 0, // Unused given DUPLICATE_SAME_ACCESS.
212 FALSE,
213 flags)) {
214 LOG(ERROR) << "DuplicateHandle() failed";
215 return false;
216 }
217 handles_for_sel_ldr->push_back(
218 reinterpret_cast<nacl::FileDescriptor>(channel));
219 #else
220 nacl::FileDescriptor channel;
221 channel.fd = sourceh;
222 channel.auto_close = close_source;
223 handles_for_sel_ldr->push_back(channel);
224 #endif
225 return true;
226 }
227
228 void CloseFile(base::File file) {
229 // The base::File destructor will close the file for us.
230 }
231
232 } // namespace 246 } // namespace
233 247
234 unsigned NaClProcessHost::keepalive_throttle_interval_milliseconds_ = 248 unsigned NaClProcessHost::keepalive_throttle_interval_milliseconds_ =
235 ppapi::kKeepaliveThrottleIntervalDefaultMilliseconds; 249 ppapi::kKeepaliveThrottleIntervalDefaultMilliseconds;
236 250
251 // Unfortunately, we cannot use ScopedGeneric directly for IPC::ChannelHandle,
252 // because there is neither operator== nor operator!= definition for
Mark Seaborn 2015/04/17 22:13:45 Did you consider defining those operators on IPC::
hidehiko 2015/04/30 16:33:02 Defining operator== or operator!= needs to be in t
253 // IPC::ChannelHandle. Instead, define a simple wrapper for IPC::ChannelHandle,
254 // here.
255 class NaClProcessHost::ScopedChannelHandle {
256 MOVE_ONLY_TYPE_FOR_CPP_03(ScopedChannelHandle, RValue);
257 public:
258 ScopedChannelHandle() {
259 }
260 ScopedChannelHandle(const IPC::ChannelHandle& handle) : handle_(handle) {
261 }
262 ScopedChannelHandle(RValue other) : handle_(other.object->handle_) {
263 other.object->handle_ = IPC::ChannelHandle();
264 }
265 ~ScopedChannelHandle() {
266 CloseIfNecessary();
267 }
268
269 const IPC::ChannelHandle& get() const { return handle_; }
270 IPC::ChannelHandle release() WARN_UNUSED_RESULT {
271 IPC::ChannelHandle result = handle_;
272 handle_ = IPC::ChannelHandle();
273 return result;
274 }
275 void reset(const IPC::ChannelHandle& handle = IPC::ChannelHandle()) {
276 // It is not allowed to reset with the same (non-invalid) handle.
Mark Seaborn 2015/04/17 22:13:45 Can you say why?
hidehiko 2015/04/30 16:33:02 Done.
277 #if defined(OS_WIN)
278 CHECK(handle.pipe.handle == NULL ||
279 handle.pipe.handle != handle_.pipe.handle);
280 #elif defined(OS_POSIX)
281 CHECK(handle.socket.fd == -1 ||
282 !handle.socket.auto_close ||
Mark Seaborn 2015/04/17 22:13:45 Why check auto_close as part of the comparison?
hidehiko 2015/04/30 16:33:02 Acknowledged.
283 handle.socket.fd != handle_.socket.fd);
284 #endif
Mark Seaborn 2015/04/17 22:13:45 "#else #error Unknown platform"?
hidehiko 2015/04/30 16:33:02 Acknowledged.
285 CloseIfNecessary();
286 handle_ = handle;
287 }
288
289 private:
290 void CloseIfNecessary() {
291 #if defined(OS_WIN)
Mark Seaborn 2015/04/17 22:13:45 How about adding a Close() method to IPC::ChannelH
hidehiko 2015/04/30 16:33:01 Again, our code depends on some constraint, so hav
292 // Defer closing task to the ScopedHandle.
293 base::win::ScopedHandle(handle_.pipe.handle);
Mark Seaborn 2015/04/17 22:13:45 Strangely, this *isn't* going through BlockingPool
hidehiko 2015/04/30 16:33:02 Acknowledged.
294 #elif defined(OS_POSIX)
295 if (handle_.socket.auto_close) {
296 // Defer closing task to the ScopedFD.
297 base::ScopedFD(handle_.socket.fd);
298 }
299 #endif
Mark Seaborn 2015/04/17 22:13:45 Ditto: add an #else #error?
hidehiko 2015/04/30 16:33:01 Acknowledged.
300 }
301
302 IPC::ChannelHandle handle_;
303 };
304
237 NaClProcessHost::NaClProcessHost( 305 NaClProcessHost::NaClProcessHost(
238 const GURL& manifest_url, 306 const GURL& manifest_url,
239 base::File nexe_file, 307 base::File nexe_file,
240 const NaClFileToken& nexe_token, 308 const NaClFileToken& nexe_token,
241 const std::vector< 309 const std::vector<
242 nacl::NaClResourceFileInfo>& prefetched_resource_files_info, 310 nacl::NaClResourceFileInfo>& prefetched_resource_files_info,
243 ppapi::PpapiPermissions permissions, 311 ppapi::PpapiPermissions permissions,
244 int render_view_id, 312 int render_view_id,
245 uint32 permission_bits, 313 uint32 permission_bits,
246 bool uses_nonsfi_mode, 314 bool uses_nonsfi_mode,
(...skipping 29 matching lines...) Expand all
276 // for this use case. 344 // for this use case.
277 process_->SetName(net::FormatUrl(manifest_url_, std::string())); 345 process_->SetName(net::FormatUrl(manifest_url_, std::string()));
278 346
279 enable_debug_stub_ = base::CommandLine::ForCurrentProcess()->HasSwitch( 347 enable_debug_stub_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
280 switches::kEnableNaClDebug); 348 switches::kEnableNaClDebug);
281 DCHECK(process_type_ != kUnknownNaClProcessType); 349 DCHECK(process_type_ != kUnknownNaClProcessType);
282 enable_crash_throttling_ = process_type_ != kNativeNaClProcessType; 350 enable_crash_throttling_ = process_type_ != kNativeNaClProcessType;
283 } 351 }
284 352
285 NaClProcessHost::~NaClProcessHost() { 353 NaClProcessHost::~NaClProcessHost() {
354 CloseFile(nexe_file_.Pass());
355
286 // Report exit status only if the process was successfully started. 356 // Report exit status only if the process was successfully started.
287 if (process_->GetData().handle != base::kNullProcessHandle) { 357 if (process_->GetData().handle != base::kNullProcessHandle) {
288 int exit_code = 0; 358 int exit_code = 0;
289 process_->GetTerminationStatus(false /* known_dead */, &exit_code); 359 process_->GetTerminationStatus(false /* known_dead */, &exit_code);
290 std::string message = 360 std::string message =
291 base::StringPrintf("NaCl process exited with status %i (0x%x)", 361 base::StringPrintf("NaCl process exited with status %i (0x%x)",
292 exit_code, exit_code); 362 exit_code, exit_code);
293 if (exit_code == 0) { 363 if (exit_code == 0) {
294 VLOG(1) << message; 364 VLOG(1) << message;
295 } else { 365 } else {
296 LOG(ERROR) << message; 366 LOG(ERROR) << message;
297 } 367 }
298 NaClBrowser::GetInstance()->OnProcessEnd(process_->GetData().id); 368 NaClBrowser::GetInstance()->OnProcessEnd(process_->GetData().id);
299 } 369 }
300 370
301 for (size_t i = 0; i < prefetched_resource_files_info_.size(); ++i) { 371 for (size_t i = 0; i < prefetched_resource_files_info_.size(); ++i) {
302 // The process failed to launch for some reason. Close resource file 372 // The process failed to launch for some reason. Close resource file
303 // handles. 373 // handles.
304 base::File file(IPC::PlatformFileForTransitToFile( 374 CloseFile(IPC::PlatformFileForTransitToFile(
305 prefetched_resource_files_info_[i].file)); 375 prefetched_resource_files_info_[i].file).Pass());
306 content::BrowserThread::GetBlockingPool()->PostTask(
307 FROM_HERE,
308 base::Bind(&CloseFile, base::Passed(file.Pass())));
309 } 376 }
310 377
311 if (reply_msg_) { 378 if (reply_msg_) {
312 // The process failed to launch for some reason. 379 // The process failed to launch for some reason.
313 // Don't keep the renderer hanging. 380 // Don't keep the renderer hanging.
314 reply_msg_->set_reply_error(); 381 reply_msg_->set_reply_error();
315 nacl_host_message_filter_->Send(reply_msg_); 382 nacl_host_message_filter_->Send(reply_msg_);
316 } 383 }
317 #if defined(OS_WIN) 384 #if defined(OS_WIN)
318 if (process_launched_by_broker_) { 385 if (process_launched_by_broker_) {
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 void NaClProcessHost::OnResourcesReady() { 742 void NaClProcessHost::OnResourcesReady() {
676 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 743 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
677 if (!nacl_browser->IsReady()) { 744 if (!nacl_browser->IsReady()) {
678 SendErrorToRenderer("could not acquire shared resources needed by NaCl"); 745 SendErrorToRenderer("could not acquire shared resources needed by NaCl");
679 delete this; 746 delete this;
680 } else if (!StartNaClExecution()) { 747 } else if (!StartNaClExecution()) {
681 delete this; 748 delete this;
682 } 749 }
683 } 750 }
684 751
685 bool NaClProcessHost::ReplyToRenderer( 752 void NaClProcessHost::ReplyToRenderer(
686 const IPC::ChannelHandle& ppapi_channel_handle, 753 ScopedChannelHandle ppapi_channel_handle,
687 const IPC::ChannelHandle& trusted_channel_handle, 754 ScopedChannelHandle trusted_channel_handle,
688 const IPC::ChannelHandle& manifest_service_channel_handle) { 755 ScopedChannelHandle manifest_service_channel_handle) {
689 #if defined(OS_WIN) 756 #if defined(OS_WIN)
690 // If we are on 64-bit Windows, the NaCl process's sandbox is 757 // If we are on 64-bit Windows, the NaCl process's sandbox is
691 // managed by a different process from the renderer's sandbox. We 758 // managed by a different process from the renderer's sandbox. We
692 // need to inform the renderer's sandbox about the NaCl process so 759 // need to inform the renderer's sandbox about the NaCl process so
693 // that the renderer can send handles to the NaCl process using 760 // that the renderer can send handles to the NaCl process using
694 // BrokerDuplicateHandle(). 761 // BrokerDuplicateHandle().
695 if (RunningOnWOW64()) { 762 if (RunningOnWOW64()) {
696 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) { 763 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
697 SendErrorToRenderer("BrokerAddTargetPeer() failed"); 764 SendErrorToRenderer("BrokerAddTargetPeer() failed");
698 return false; 765 return;
699 } 766 }
700 } 767 }
701 #endif 768 #endif
702 769
703 FileDescriptor imc_handle_for_renderer; 770 ScopedPlatformFileForTransit imc_handle_for_renderer(
704 #if defined(OS_WIN) 771 IPC::TakeFileHandleForProcess(socket_for_renderer_.Pass(),
705 // Copy the handle into the renderer process. 772 nacl_host_message_filter_->PeerHandle()));
706 HANDLE handle_in_renderer; 773 if (!imc_handle_for_renderer.is_valid()) {
707 if (!DuplicateHandle(base::GetCurrentProcessHandle(), 774 SendErrorToRenderer("TakeFileHandleForProcess() failed");
708 socket_for_renderer_.TakePlatformFile(), 775 return;
709 nacl_host_message_filter_->PeerHandle(),
710 &handle_in_renderer,
711 0, // Unused given DUPLICATE_SAME_ACCESS.
712 FALSE,
713 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
714 SendErrorToRenderer("DuplicateHandle() failed");
715 return false;
716 } 776 }
717 imc_handle_for_renderer = reinterpret_cast<FileDescriptor>( 777
718 handle_in_renderer); 778 ScopedSharedMemoryHandle crash_info_shmem_renderer_handle;
Mark Seaborn 2015/04/17 22:13:45 I think this is unsafe on Windows. Remember, on W
hidehiko 2015/04/30 16:33:02 You're right. Fixed.
719 #else 779 {
720 // No need to dup the imc_handle - we don't pass it anywhere else so 780 base::SharedMemoryHandle raw_handle = base::SharedMemory::NULLHandle();
721 // it cannot be closed. 781 if (crash_info_shmem_.ShareToProcess(
722 FileDescriptor imc_handle; 782 nacl_host_message_filter_->PeerHandle(), &raw_handle)) {
723 imc_handle.fd = socket_for_renderer_.TakePlatformFile(); 783 crash_info_shmem_renderer_handle.reset(raw_handle);
724 imc_handle.auto_close = true; 784 }
725 imc_handle_for_renderer = imc_handle; 785 }
726 #endif 786 if (!crash_info_shmem_renderer_handle.is_valid()) {
787 SendErrorToRenderer("ShareToProcess() failed");
788 return;
789 }
727 790
728 const ChildProcessData& data = process_->GetData(); 791 const ChildProcessData& data = process_->GetData();
729 base::SharedMemoryHandle crash_info_shmem_renderer_handle; 792 if (SendMessageToRenderer(
730 if (!crash_info_shmem_.ShareToProcess(nacl_host_message_filter_->PeerHandle(), 793 NaClLaunchResult(imc_handle_for_renderer.get(),
731 &crash_info_shmem_renderer_handle)) { 794 ppapi_channel_handle.get(),
732 SendErrorToRenderer("ShareToProcess() failed"); 795 trusted_channel_handle.get(),
733 return false; 796 manifest_service_channel_handle.get(),
797 base::GetProcId(data.handle),
798 data.id,
799 crash_info_shmem_renderer_handle.get()),
800 std::string() /* error_message */)) {
801 // On success, the NaClLaunchResult is sent to renderer, so that the
802 // handles have been delegated to the message.
803 ignore_result(imc_handle_for_renderer.release());
804 ignore_result(ppapi_channel_handle.release());
805 ignore_result(trusted_channel_handle.release());
806 ignore_result(manifest_service_channel_handle.release());
807 ignore_result(crash_info_shmem_renderer_handle.release());
734 } 808 }
735 809
736 SendMessageToRenderer(
737 NaClLaunchResult(imc_handle_for_renderer,
738 ppapi_channel_handle,
739 trusted_channel_handle,
740 manifest_service_channel_handle,
741 base::GetProcId(data.handle),
742 data.id,
743 crash_info_shmem_renderer_handle),
744 std::string() /* error_message */);
745
746 // Now that the crash information shmem handles have been shared with the 810 // Now that the crash information shmem handles have been shared with the
747 // plugin and the renderer, the browser can close its handle. 811 // plugin and the renderer, the browser can close its handle.
748 crash_info_shmem_.Close(); 812 crash_info_shmem_.Close();
749 return true;
750 } 813 }
751 814
752 void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) { 815 void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) {
753 LOG(ERROR) << "NaCl process launch failed: " << error_message; 816 LOG(ERROR) << "NaCl process launch failed: " << error_message;
754 SendMessageToRenderer(NaClLaunchResult(), error_message); 817 SendMessageToRenderer(NaClLaunchResult(), error_message);
755 } 818 }
756 819
757 void NaClProcessHost::SendMessageToRenderer( 820 bool NaClProcessHost::SendMessageToRenderer(
758 const NaClLaunchResult& result, 821 const NaClLaunchResult& result,
759 const std::string& error_message) { 822 const std::string& error_message) {
760 DCHECK(nacl_host_message_filter_.get()); 823 DCHECK(nacl_host_message_filter_.get());
761 DCHECK(reply_msg_); 824 DCHECK(reply_msg_);
762 if (nacl_host_message_filter_.get() != NULL && reply_msg_ != NULL) { 825 if (nacl_host_message_filter_.get() == NULL || reply_msg_ == NULL) {
763 NaClHostMsg_LaunchNaCl::WriteReplyParams( 826 return false;
764 reply_msg_, result, error_message);
765 nacl_host_message_filter_->Send(reply_msg_);
766 nacl_host_message_filter_ = NULL;
767 reply_msg_ = NULL;
768 } 827 }
828 NaClHostMsg_LaunchNaCl::WriteReplyParams(reply_msg_, result, error_message);
829 nacl_host_message_filter_->Send(reply_msg_);
830 nacl_host_message_filter_ = NULL;
831 reply_msg_ = NULL;
832 return true;
769 } 833 }
770 834
771 void NaClProcessHost::SetDebugStubPort(int port) { 835 void NaClProcessHost::SetDebugStubPort(int port) {
772 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 836 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
773 nacl_browser->SetProcessGdbDebugStubPort(process_->GetData().id, port); 837 nacl_browser->SetProcessGdbDebugStubPort(process_->GetData().id, port);
774 } 838 }
775 839
776 #if defined(OS_POSIX) 840 #if defined(OS_POSIX)
777 // TCP port we chose for NaCl debug stub. It can be any other number. 841 // TCP port we chose for NaCl debug stub. It can be any other number.
778 static const uint16_t kInitialDebugStubPort = 4014; 842 static const uint16_t kInitialDebugStubPort = 4014;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
817 bool NaClProcessHost::StartNaClExecution() { 881 bool NaClProcessHost::StartNaClExecution() {
818 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 882 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
819 883
820 NaClStartParams params; 884 NaClStartParams params;
821 885
822 // Enable PPAPI proxy channel creation only for renderer processes. 886 // Enable PPAPI proxy channel creation only for renderer processes.
823 params.enable_ipc_proxy = enable_ppapi_proxy(); 887 params.enable_ipc_proxy = enable_ppapi_proxy();
824 params.process_type = process_type_; 888 params.process_type = process_type_;
825 bool enable_nacl_debug = enable_debug_stub_ && 889 bool enable_nacl_debug = enable_debug_stub_ &&
826 NaClBrowser::GetDelegate()->URLMatchesDebugPatterns(manifest_url_); 890 NaClBrowser::GetDelegate()->URLMatchesDebugPatterns(manifest_url_);
891
892 // Because this function may return early on failure, so keep the resources
893 // in local variables, and pass them to params later.
894 ScopedPlatformFileForTransit socket_for_sel_ldr;
895 ScopedPlatformFileForTransit irt_file;
896 #if defined(OS_MACOSX)
897 base::ScopedFD memory_fd;
898 #endif
899 #if defined(OS_POSIX)
900 base::ScopedFD debug_stub_server_bound_socket;
901 #endif
902
827 if (uses_nonsfi_mode_) { 903 if (uses_nonsfi_mode_) {
828 // Currently, non-SFI mode is supported only on Linux. 904 // Currently, non-SFI mode is supported only on Linux.
829 #if defined(OS_LINUX) 905 #if defined(OS_LINUX)
830 // In non-SFI mode, we do not use SRPC. Make sure that the socketpair is 906 // In non-SFI mode, we do not use SRPC. Make sure that the socketpair is
831 // not created. 907 // not created.
832 DCHECK(!socket_for_sel_ldr_.IsValid()); 908 DCHECK(!socket_for_sel_ldr_.IsValid());
833 #endif 909 #endif
834 if (enable_nacl_debug) { 910 if (enable_nacl_debug) {
835 base::ProcessId pid = base::GetProcId(process_->GetData().handle); 911 base::ProcessId pid = base::GetProcId(process_->GetData().handle);
836 LOG(WARNING) << "nonsfi nacl plugin running in " << pid; 912 LOG(WARNING) << "nonsfi nacl plugin running in " << pid;
837 } 913 }
838 } else { 914 } else {
839 params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled(); 915 params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled();
840 params.validation_cache_key = nacl_browser->GetValidationCacheKey(); 916 params.validation_cache_key = nacl_browser->GetValidationCacheKey();
841 params.version = NaClBrowser::GetDelegate()->GetVersionString(); 917 params.version = NaClBrowser::GetDelegate()->GetVersionString();
842 params.enable_debug_stub = enable_nacl_debug; 918 params.enable_debug_stub = enable_nacl_debug;
843 params.enable_mojo = base::CommandLine::ForCurrentProcess()->HasSwitch( 919 params.enable_mojo = base::CommandLine::ForCurrentProcess()->HasSwitch(
844 switches::kEnableNaClMojo); 920 switches::kEnableNaClMojo);
845 921
846 const ChildProcessData& data = process_->GetData(); 922 const ChildProcessData& data = process_->GetData();
847 if (!ShareHandleToSelLdr(data.handle, 923 socket_for_sel_ldr.reset(
848 socket_for_sel_ldr_.TakePlatformFile(), 924 IPC::TakeFileHandleForProcess(socket_for_sel_ldr_.Pass(),
849 true, 925 data.handle));
850 &params.handles)) { 926 if (!socket_for_sel_ldr.is_valid()) {
851 return false; 927 return false;
852 } 928 }
853 929
854 const base::File& irt_file = nacl_browser->IrtFile(); 930 const base::File& original_irt_file = nacl_browser->IrtFile();
855 CHECK(irt_file.IsValid()); 931 CHECK(original_irt_file.IsValid());
856 // Send over the IRT file handle. We don't close our own copy! 932 // Send over the IRT file handle. We don't close our own copy!
857 if (!ShareHandleToSelLdr(data.handle, irt_file.GetPlatformFile(), false, 933 irt_file.reset(IPC::GetFileHandleForProcess(
858 &params.handles)) { 934 original_irt_file.GetPlatformFile(), data.handle, false));
935 if (!irt_file.is_valid()) {
936 DLOG(ERROR) << "Failed to create irt_file handler for plugin.";
859 return false; 937 return false;
860 } 938 }
861 939
862 #if defined(OS_MACOSX) 940 #if defined(OS_MACOSX)
863 // For dynamic loading support, NaCl requires a file descriptor that 941 // For dynamic loading support, NaCl requires a file descriptor that
864 // was created in /tmp, since those created with shm_open() are not 942 // was created in /tmp, since those created with shm_open() are not
865 // mappable with PROT_EXEC. Rather than requiring an extra IPC 943 // mappable with PROT_EXEC. Rather than requiring an extra IPC
866 // round trip out of the sandbox, we create an FD here. 944 // round trip out of the sandbox, we create an FD here.
867 base::SharedMemory memory_buffer; 945 base::SharedMemory memory_buffer;
868 base::SharedMemoryCreateOptions options; 946 base::SharedMemoryCreateOptions options;
869 options.size = 1; 947 options.size = 1;
870 options.executable = true; 948 options.executable = true;
871 if (!memory_buffer.Create(options)) { 949 if (!memory_buffer.Create(options)) {
872 DLOG(ERROR) << "Failed to allocate memory buffer"; 950 DLOG(ERROR) << "Failed to allocate memory buffer";
873 return false; 951 return false;
874 } 952 }
875 FileDescriptor memory_fd; 953 memory_fd.reset(dup(memory_buffer.handle().fd));
876 memory_fd.fd = dup(memory_buffer.handle().fd); 954 if (!memory_fd.is_valid()) {
877 if (memory_fd.fd < 0) {
878 DLOG(ERROR) << "Failed to dup() a file descriptor"; 955 DLOG(ERROR) << "Failed to dup() a file descriptor";
879 return false; 956 return false;
880 } 957 }
881 memory_fd.auto_close = true;
882 params.handles.push_back(memory_fd);
883 #endif 958 #endif
884 959
885 #if defined(OS_POSIX) 960 #if defined(OS_POSIX)
886 if (params.enable_debug_stub) { 961 if (params.enable_debug_stub) {
887 net::SocketDescriptor server_bound_socket = GetDebugStubSocketHandle(); 962 net::SocketDescriptor server_bound_socket = GetDebugStubSocketHandle();
888 if (server_bound_socket != net::kInvalidSocket) { 963 if (server_bound_socket != net::kInvalidSocket) {
889 params.debug_stub_server_bound_socket = 964 debug_stub_server_bound_socket.reset(server_bound_socket);
890 FileDescriptor(server_bound_socket, true);
891 } 965 }
892 } 966 }
893 #endif 967 #endif
894 } 968 }
895 969
896 if (!crash_info_shmem_.ShareToProcess(process_->GetData().handle, 970 ScopedSharedMemoryHandle crash_info_shmem_handle;
897 &params.crash_info_shmem_handle)) { 971 {
972 base::SharedMemoryHandle raw_handle;
973 if (crash_info_shmem_.ShareToProcess(
974 process_->GetData().handle, &raw_handle)) {
975 crash_info_shmem_handle.reset(raw_handle);
976 }
977 }
978 if (!crash_info_shmem_handle.is_valid()) {
898 DLOG(ERROR) << "Failed to ShareToProcess() a shared memory buffer"; 979 DLOG(ERROR) << "Failed to ShareToProcess() a shared memory buffer";
899 return false; 980 return false;
900 } 981 }
901 982
902 base::FilePath file_path; 983 // Hereafter, NaClProcessMsg_Start must be (eventually) sent.
984 // Delegate the resources to NaClStartParams.
985 params.crash_info_shmem_handle = crash_info_shmem_handle.release();
903 if (uses_nonsfi_mode_) { 986 if (uses_nonsfi_mode_) {
987 DCHECK(!socket_for_sel_ldr.is_valid());
988 DCHECK(!irt_file.is_valid());
989 #if defined(OS_MACOSX)
990 DCHECK(!memory_fd.is_valid());
991 #endif
992
904 // Don't retrieve the file path when using nonsfi mode; there's no 993 // Don't retrieve the file path when using nonsfi mode; there's no
905 // validation caching in that case, so it's unnecessary work, and would 994 // validation caching in that case, so it's unnecessary work, and would
906 // expose the file path to the plugin. 995 // expose the file path to the plugin.
907 996
908 // Pass the pre-opened resource files to the loader. For the same reason 997 // Pass the pre-opened resource files to the loader. For the same reason
909 // as above, use an empty base::FilePath. 998 // as above, use an empty base::FilePath.
910 for (size_t i = 0; i < prefetched_resource_files_info_.size(); ++i) { 999 for (size_t i = 0; i < prefetched_resource_files_info_.size(); ++i) {
911 params.prefetched_resource_files.push_back( 1000 params.prefetched_resource_files.push_back(
912 NaClResourceFileInfo(prefetched_resource_files_info_[i].file, 1001 NaClResourceFileInfo(prefetched_resource_files_info_[i].file,
913 base::FilePath(), 1002 base::FilePath(),
914 prefetched_resource_files_info_[i].file_key)); 1003 prefetched_resource_files_info_[i].file_key));
915 } 1004 }
916 prefetched_resource_files_info_.clear(); 1005 prefetched_resource_files_info_.clear();
917 } else { 1006 } else {
1007 // TODO(yusukes): Handle |prefetched_resource_files_info_| for SFI-NaCl.
1008 DCHECK(prefetched_resource_files_info_.empty());
1009
1010 params.handles.push_back(socket_for_sel_ldr.release());
1011 params.handles.push_back(irt_file.release());
1012 // Note that on OS_POSIX (including OS_MACOSX), IPC::PlatformFileForTransit
1013 // is the alias of base::FileDescriptor.
1014 #if defined(OS_MACOSX)
1015 params.handles.push_back(base::FileDescriptor(memory_fd.release(), true));
1016 #endif
1017 #if defined(OS_POSIX)
1018 if (debug_stub_server_bound_socket.is_valid()) {
1019 params.debug_stub_server_bound_socket =
1020 base::FileDescriptor(debug_stub_server_bound_socket.release(), true);
1021 }
1022 #endif
1023 }
1024
1025 if (!uses_nonsfi_mode_) {
1026 base::FilePath file_path;
918 if (NaClBrowser::GetInstance()->GetFilePath(nexe_token_.lo, 1027 if (NaClBrowser::GetInstance()->GetFilePath(nexe_token_.lo,
919 nexe_token_.hi, 1028 nexe_token_.hi,
920 &file_path)) { 1029 &file_path)) {
921 // We have to reopen the file in the browser process; we don't want a 1030 // We have to reopen the file in the browser process; we don't want a
922 // compromised renderer to pass an arbitrary fd that could get loaded 1031 // compromised renderer to pass an arbitrary fd that could get loaded
923 // into the plugin process. 1032 // into the plugin process.
924 if (base::PostTaskAndReplyWithResult( 1033 if (base::PostTaskAndReplyWithResult(
hidehiko 2015/04/17 07:25:32 Note: this code also has a potential resource leak
925 content::BrowserThread::GetBlockingPool(), 1034 content::BrowserThread::GetBlockingPool(),
926 FROM_HERE, 1035 FROM_HERE,
927 base::Bind(OpenNaClReadExecImpl, 1036 base::Bind(OpenNaClReadExecImpl,
928 file_path, 1037 file_path,
929 true /* is_executable */), 1038 true /* is_executable */),
930 base::Bind(&NaClProcessHost::StartNaClFileResolved, 1039 base::Bind(&NaClProcessHost::StartNaClFileResolved,
931 weak_factory_.GetWeakPtr(), 1040 weak_factory_.GetWeakPtr(),
932 params, 1041 params,
933 file_path))) { 1042 file_path))) {
934 return true; 1043 return true;
935 } 1044 }
936 } 1045 }
937 // TODO(yusukes): Handle |prefetched_resource_files_info_| for SFI-NaCl.
938 DCHECK(prefetched_resource_files_info_.empty());
939 } 1046 }
940 1047
941 params.nexe_file = IPC::TakeFileHandleForProcess(nexe_file_.Pass(), 1048 params.nexe_file = IPC::TakeFileHandleForProcess(nexe_file_.Pass(),
942 process_->GetData().handle); 1049 process_->GetData().handle);
943 process_->Send(new NaClProcessMsg_Start(params)); 1050 process_->Send(new NaClProcessMsg_Start(params));
944 return true; 1051 return true;
945 } 1052 }
946 1053
947 void NaClProcessHost::StartNaClFileResolved( 1054 void NaClProcessHost::StartNaClFileResolved(
948 NaClStartParams params, 1055 NaClStartParams params,
949 const base::FilePath& file_path, 1056 const base::FilePath& file_path,
950 base::File checked_nexe_file) { 1057 base::File checked_nexe_file) {
951 if (checked_nexe_file.IsValid()) { 1058 if (checked_nexe_file.IsValid()) {
952 // Release the file received from the renderer. This has to be done on a 1059 // Release the file received from the renderer.
953 // thread where IO is permitted, though. 1060 CloseFile(nexe_file_.Pass());
954 content::BrowserThread::GetBlockingPool()->PostTask(
955 FROM_HERE,
956 base::Bind(&CloseFile, base::Passed(nexe_file_.Pass())));
957 params.nexe_file_path_metadata = file_path; 1061 params.nexe_file_path_metadata = file_path;
958 params.nexe_file = IPC::TakeFileHandleForProcess( 1062 params.nexe_file = IPC::TakeFileHandleForProcess(
959 checked_nexe_file.Pass(), process_->GetData().handle); 1063 checked_nexe_file.Pass(), process_->GetData().handle);
960 } else { 1064 } else {
961 params.nexe_file = IPC::TakeFileHandleForProcess( 1065 params.nexe_file = IPC::TakeFileHandleForProcess(
962 nexe_file_.Pass(), process_->GetData().handle); 1066 nexe_file_.Pass(), process_->GetData().handle);
963 } 1067 }
964 process_->Send(new NaClProcessMsg_Start(params)); 1068 process_->Send(new NaClProcessMsg_Start(params));
965 } 1069 }
966 1070
967 // This method is called when NaClProcessHostMsg_PpapiChannelCreated is 1071 // This method is called when NaClProcessHostMsg_PpapiChannelCreated is
968 // received. 1072 // received.
969 void NaClProcessHost::OnPpapiChannelsCreated( 1073 void NaClProcessHost::OnPpapiChannelsCreated(
970 const IPC::ChannelHandle& browser_channel_handle, 1074 const IPC::ChannelHandle& raw_browser_channel_handle,
971 const IPC::ChannelHandle& ppapi_renderer_channel_handle, 1075 const IPC::ChannelHandle& raw_ppapi_renderer_channel_handle,
972 const IPC::ChannelHandle& trusted_renderer_channel_handle, 1076 const IPC::ChannelHandle& raw_trusted_renderer_channel_handle,
973 const IPC::ChannelHandle& manifest_service_channel_handle) { 1077 const IPC::ChannelHandle& raw_manifest_service_channel_handle) {
1078 ScopedChannelHandle browser_channel_handle(raw_browser_channel_handle);
1079 ScopedChannelHandle ppapi_renderer_channel_handle(
1080 raw_ppapi_renderer_channel_handle);
1081 ScopedChannelHandle trusted_renderer_channel_handle(
1082 raw_trusted_renderer_channel_handle);
1083 ScopedChannelHandle manifest_service_channel_handle(
1084 raw_manifest_service_channel_handle);
974 if (!enable_ppapi_proxy()) { 1085 if (!enable_ppapi_proxy()) {
975 ReplyToRenderer(IPC::ChannelHandle(), 1086 ReplyToRenderer(ScopedChannelHandle(),
976 trusted_renderer_channel_handle, 1087 trusted_renderer_channel_handle.Pass(),
977 manifest_service_channel_handle); 1088 manifest_service_channel_handle.Pass());
978 return; 1089 return;
979 } 1090 }
980 1091
981 if (!ipc_proxy_channel_.get()) { 1092 if (!ipc_proxy_channel_.get()) {
982 DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type); 1093 DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type);
983 1094
984 ipc_proxy_channel_ = 1095 ipc_proxy_channel_ =
985 IPC::ChannelProxy::Create(browser_channel_handle, 1096 IPC::ChannelProxy::Create(browser_channel_handle.release(),
986 IPC::Channel::MODE_CLIENT, 1097 IPC::Channel::MODE_CLIENT,
987 NULL, 1098 NULL,
988 base::MessageLoopProxy::current().get()); 1099 base::MessageLoopProxy::current().get());
989 // Create the browser ppapi host and enable PPAPI message dispatching to the 1100 // Create the browser ppapi host and enable PPAPI message dispatching to the
990 // browser process. 1101 // browser process.
991 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess( 1102 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
992 ipc_proxy_channel_.get(), // sender 1103 ipc_proxy_channel_.get(), // sender
993 permissions_, 1104 permissions_,
994 process_->GetData().handle, 1105 process_->GetData().handle,
995 ipc_proxy_channel_.get(), 1106 ipc_proxy_channel_.get(),
(...skipping 24 matching lines...) Expand all
1020 1131
1021 ppapi_host_->GetPpapiHost()->AddHostFactoryFilter( 1132 ppapi_host_->GetPpapiHost()->AddHostFactoryFilter(
1022 scoped_ptr<ppapi::host::HostFactory>( 1133 scoped_ptr<ppapi::host::HostFactory>(
1023 NaClBrowser::GetDelegate()->CreatePpapiHostFactory( 1134 NaClBrowser::GetDelegate()->CreatePpapiHostFactory(
1024 ppapi_host_.get()))); 1135 ppapi_host_.get())));
1025 1136
1026 // Send a message to initialize the IPC dispatchers in the NaCl plugin. 1137 // Send a message to initialize the IPC dispatchers in the NaCl plugin.
1027 ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args)); 1138 ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args));
1028 1139
1029 // Let the renderer know that the IPC channels are established. 1140 // Let the renderer know that the IPC channels are established.
1030 ReplyToRenderer(ppapi_renderer_channel_handle, 1141 ReplyToRenderer(ppapi_renderer_channel_handle.Pass(),
1031 trusted_renderer_channel_handle, 1142 trusted_renderer_channel_handle.Pass(),
1032 manifest_service_channel_handle); 1143 manifest_service_channel_handle.Pass());
1033 } else { 1144 } else {
1034 // Attempt to open more than 1 browser channel is not supported. 1145 // Attempt to open more than 1 browser channel is not supported.
1035 // Shut down the NaCl process. 1146 // Shut down the NaCl process.
1036 process_->GetHost()->ForceShutdown(); 1147 process_->GetHost()->ForceShutdown();
1037 } 1148 }
1038 } 1149 }
1039 1150
1040 bool NaClProcessHost::StartWithLaunchedProcess() { 1151 bool NaClProcessHost::StartWithLaunchedProcess() {
1041 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 1152 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
1042 1153
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
1208 process.Pass(), info, 1319 process.Pass(), info,
1209 base::MessageLoopProxy::current(), 1320 base::MessageLoopProxy::current(),
1210 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker, 1321 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker,
1211 weak_factory_.GetWeakPtr())); 1322 weak_factory_.GetWeakPtr()));
1212 return true; 1323 return true;
1213 } 1324 }
1214 } 1325 }
1215 #endif 1326 #endif
1216 1327
1217 } // namespace nacl 1328 } // namespace nacl
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698