Index: chrome/browser/child_process_context.cc |
=================================================================== |
--- chrome/browser/child_process_context.cc (revision 0) |
+++ chrome/browser/child_process_context.cc (revision 0) |
@@ -0,0 +1,225 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/child_process_context.h" |
+ |
+#include "chrome/browser/chrome_thread.h" |
+#include "chrome/common/child_process_info.h" |
+#include "chrome/common/notification_type.h" |
+#include "chrome/common/result_codes.h" |
+#include "chrome/common/chrome_descriptors.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "chrome/common/process_watcher.h" |
+ |
+#if defined(OS_WIN) |
+#include "chrome/common/sandbox_policy.h" |
+#elif defined(OS_LINUX) |
+#include "base/singleton.h" |
+#include "chrome/browser/crash_handler_host_linux.h" |
+#include "chrome/browser/zygote_host_linux.h" |
+#include "chrome/browser/renderer_host/render_sandbox_host_linux.h" |
+#endif |
+ |
+#if defined(OS_MACOSX) |
+#include "chrome/browser/mach_broker_mac.h" |
+#endif |
+ |
+#if defined(OS_POSIX) |
+#include "base/global_descriptors_posix.h" |
+#endif |
+ |
+// TODO(eroman): Debugging helper to make strings show up in mini-dumps. |
+// Remove after done investigating 40447. |
+class StackString { |
+ public: |
+ explicit StackString(const std::wstring& str) { |
+ length_ = str.size(); |
+ memcpy(&buffer_[0], str.data(), |
+ std::min(sizeof(wchar_t) * str.length(), |
+ sizeof(buffer_))); |
+ } |
+ |
+ std::wstring ToString() { |
+ return std::wstring(buffer_, length_); |
+ } |
+ |
+ ~StackString() { |
+ // Hack to make sure compiler doesn't optimize us away. |
+ if (ToString() != ToString()) |
+ LOG(INFO) << ToString(); |
+ } |
+ |
+ private: |
+ wchar_t buffer_[128]; |
+ size_t length_; |
+}; |
+ |
+ChildProcessContext::ChildProcessContext() { |
+} |
+ |
+int ChildProcessContext::GetBadMessageResultCode() { |
+ return ResultCodes::KILLED_BAD_MESSAGE; |
+} |
+ |
+int ChildProcessContext::GetNormalExitResultCode() { |
+ return ResultCodes::NORMAL_EXIT; |
+} |
+ |
+std::string ChildProcessContext::GenerateRandomChannelID(void* instance) { |
+ return ChildProcessInfo::GenerateRandomChannelID(instance); |
+} |
+ |
+bool ChildProcessContext::GetCurrentThreadIdentifier(int* identifier) { |
+ ChromeThread::ID chrome_id; |
+ if (ChromeThread::GetCurrentThreadIdentifier(&chrome_id)) { |
+ *identifier = static_cast<int>(chrome_id); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool ChildProcessContext::CurrentlyOnThread(int identifier) { |
+ return ChromeThread::CurrentlyOn(static_cast<ChromeThread::ID>(identifier)); |
+} |
+ |
+bool ChildProcessContext::PostTask(int identifier, |
+ const tracked_objects::Location& from_here, |
+ Task* task) { |
+ return ChromeThread::PostTask(static_cast<ChromeThread::ID>(identifier), |
+ from_here, task); |
+} |
+ |
+bool ChildProcessContext::PostProcessLauncherTask( |
+ const tracked_objects::Location& from_here, |
+ Task* task) { |
+ return ChromeThread::PostTask(ChromeThread::PROCESS_LAUNCHER, from_here, |
+ task); |
+} |
+ |
+base::ProcessHandle ChildProcessContext::StartProcess( |
+#if defined(OS_WIN) |
+ const FilePath& exposed_dir, |
+#elif defined(OS_POSIX) |
+ bool use_zygote, |
+ const base::environment_vector& environ, |
+ int ipcfd, |
+#endif |
+ CommandLine* cmd_line) { |
+ base::ProcessHandle handle = base::kNullProcessHandle; |
+#if defined(OS_WIN) |
+ // TODO(eroman): Remove after done investigating 40447. |
+ StackString stack_command_line(cmd_line->command_line_string()); |
+ // This line might crash, since it calls the string copy-constructor: |
+ StackString stack_program(cmd_line->program()); |
+ |
+ handle = sandbox::StartProcessWithAccess(cmd_line, exposed_dir); |
+#elif defined(OS_POSIX) |
+ |
+#if defined(OS_LINUX) |
+ if (use_zygote) { |
+ base::GlobalDescriptors::Mapping mapping; |
+ mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd)); |
+ const int crash_signal_fd = |
+ Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket(); |
+ if (crash_signal_fd >= 0) { |
+ mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal, |
+ crash_signal_fd)); |
+ } |
+ handle = Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping); |
+ } else |
+ // Fall through to the normal posix case below when we're not zygoting. |
+#endif |
+ { |
+ base::file_handle_mapping_vector fds_to_map; |
+ fds_to_map.push_back(std::make_pair( |
+ ipcfd, |
+ kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor)); |
+ |
+#if defined(OS_LINUX) |
+ // On Linux, we need to add some extra file descriptors for crash handling |
+ // and the sandbox. |
+ bool is_renderer = |
+ cmd_line->GetSwitchValueASCII(switches::kProcessType) == |
+ switches::kRendererProcess; |
+ bool is_plugin = |
+ cmd_line->GetSwitchValueASCII(switches::kProcessType) == |
+ switches::kPluginProcess; |
+ |
+ if (is_renderer || is_plugin) { |
+ int crash_signal_fd; |
+ if (is_renderer) { |
+ crash_signal_fd = Singleton<RendererCrashHandlerHostLinux>()-> |
+ GetDeathSignalSocket(); |
+ } else { |
+ crash_signal_fd = Singleton<PluginCrashHandlerHostLinux>()-> |
+ GetDeathSignalSocket(); |
+ } |
+ if (crash_signal_fd >= 0) { |
+ fds_to_map.push_back(std::make_pair( |
+ crash_signal_fd, |
+ kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor)); |
+ } |
+ } |
+ if (is_renderer) { |
+ const int sandbox_fd = |
+ Singleton<RenderSandboxHostLinux>()->GetRendererSocket(); |
+ fds_to_map.push_back(std::make_pair( |
+ sandbox_fd, |
+ kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor)); |
+ } |
+#endif // defined(OS_LINUX) |
+ |
+ // Actually launch the app. |
+ bool launched; |
+#if defined(OS_MACOSX) |
+ task_t child_task; |
+ launched = base::LaunchAppAndGetTask( |
+ cmd_line->argv(), env, fds_to_map, false, &child_task, &handle); |
+ if (launched && child_task != MACH_PORT_NULL) { |
+ MachBroker::instance()->RegisterPid( |
+ handle, |
+ MachBroker::MachInfo().SetTask(child_task)); |
+ } |
+#else |
+ launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map, |
+ /* wait= */false, &handle); |
+#endif |
+ if (!launched) |
+ handle = base::kNullProcessHandle; |
+ } |
+#endif // else defined(OS_POSIX) |
+ |
+ return handle; |
+} |
+ |
+void ChildProcessContext::EnsureProcessTerminated(base::ProcessHandle) { |
+ // On POSIX, we must additionally reap the child. |
+#if defined(OS_POSIX) |
+#if defined(OS_LINUX) |
+ if (zygote) { |
+ // If the renderer was created via a zygote, we have to proxy the reaping |
+ // through the zygote process. |
+ Singleton<ZygoteHost>()->EnsureProcessTerminated(handle); |
+ } else |
+#endif // OS_LINUX |
+ { |
+ ProcessWatcher::EnsureProcessTerminated(handle); |
+ } |
+#endif // OS_POSIX |
+} |
+ |
+bool ChildProcessContext::CheckProcessCrash(bool* child_exited, |
+#if defined(OS_POSIX) |
+ bool use_zygote, |
+#endif |
+ base::ProcessHandle handle) { |
+#if defined(OS_LINUX) |
+ if (use_zygote) { |
+ return Singleton<ZygoteHost>()->DidProcessCrash(handle, child_exited); |
+ } else |
+#endif |
+ { |
+ return base::DidProcessCrash(child_exited, handle); |
+ } |
+} |