OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/child_process_context.h" |
| 6 |
| 7 #include "chrome/browser/chrome_thread.h" |
| 8 #include "chrome/common/child_process_info.h" |
| 9 #include "chrome/common/notification_type.h" |
| 10 #include "chrome/common/result_codes.h" |
| 11 #include "chrome/common/chrome_descriptors.h" |
| 12 #include "chrome/common/chrome_switches.h" |
| 13 #include "chrome/common/process_watcher.h" |
| 14 |
| 15 #if defined(OS_WIN) |
| 16 #include "chrome/common/sandbox_policy.h" |
| 17 #elif defined(OS_LINUX) |
| 18 #include "base/singleton.h" |
| 19 #include "chrome/browser/crash_handler_host_linux.h" |
| 20 #include "chrome/browser/zygote_host_linux.h" |
| 21 #include "chrome/browser/renderer_host/render_sandbox_host_linux.h" |
| 22 #endif |
| 23 |
| 24 #if defined(OS_MACOSX) |
| 25 #include "chrome/browser/mach_broker_mac.h" |
| 26 #endif |
| 27 |
| 28 #if defined(OS_POSIX) |
| 29 #include "base/global_descriptors_posix.h" |
| 30 #endif |
| 31 |
| 32 // TODO(eroman): Debugging helper to make strings show up in mini-dumps. |
| 33 // Remove after done investigating 40447. |
| 34 class StackString { |
| 35 public: |
| 36 explicit StackString(const std::wstring& str) { |
| 37 length_ = str.size(); |
| 38 memcpy(&buffer_[0], str.data(), |
| 39 std::min(sizeof(wchar_t) * str.length(), |
| 40 sizeof(buffer_))); |
| 41 } |
| 42 |
| 43 std::wstring ToString() { |
| 44 return std::wstring(buffer_, length_); |
| 45 } |
| 46 |
| 47 ~StackString() { |
| 48 // Hack to make sure compiler doesn't optimize us away. |
| 49 if (ToString() != ToString()) |
| 50 LOG(INFO) << ToString(); |
| 51 } |
| 52 |
| 53 private: |
| 54 wchar_t buffer_[128]; |
| 55 size_t length_; |
| 56 }; |
| 57 |
| 58 ChildProcessContext::ChildProcessContext() { |
| 59 } |
| 60 |
| 61 int ChildProcessContext::GetBadMessageResultCode() { |
| 62 return ResultCodes::KILLED_BAD_MESSAGE; |
| 63 } |
| 64 |
| 65 int ChildProcessContext::GetNormalExitResultCode() { |
| 66 return ResultCodes::NORMAL_EXIT; |
| 67 } |
| 68 |
| 69 std::string ChildProcessContext::GenerateRandomChannelID(void* instance) { |
| 70 return ChildProcessInfo::GenerateRandomChannelID(instance); |
| 71 } |
| 72 |
| 73 bool ChildProcessContext::GetCurrentThreadIdentifier(int* identifier) { |
| 74 ChromeThread::ID chrome_id; |
| 75 if (ChromeThread::GetCurrentThreadIdentifier(&chrome_id)) { |
| 76 *identifier = static_cast<int>(chrome_id); |
| 77 return true; |
| 78 } |
| 79 return false; |
| 80 } |
| 81 |
| 82 bool ChildProcessContext::CurrentlyOnThread(int identifier) { |
| 83 return ChromeThread::CurrentlyOn(static_cast<ChromeThread::ID>(identifier)); |
| 84 } |
| 85 |
| 86 bool ChildProcessContext::PostTask(int identifier, |
| 87 const tracked_objects::Location& from_here, |
| 88 Task* task) { |
| 89 return ChromeThread::PostTask(static_cast<ChromeThread::ID>(identifier), |
| 90 from_here, task); |
| 91 } |
| 92 |
| 93 bool ChildProcessContext::PostProcessLauncherTask( |
| 94 const tracked_objects::Location& from_here, |
| 95 Task* task) { |
| 96 return ChromeThread::PostTask(ChromeThread::PROCESS_LAUNCHER, from_here, |
| 97 task); |
| 98 } |
| 99 |
| 100 base::ProcessHandle ChildProcessContext::StartProcess( |
| 101 #if defined(OS_WIN) |
| 102 const FilePath& exposed_dir, |
| 103 #elif defined(OS_POSIX) |
| 104 bool use_zygote, |
| 105 const base::environment_vector& environ, |
| 106 int ipcfd, |
| 107 #endif |
| 108 CommandLine* cmd_line) { |
| 109 base::ProcessHandle handle = base::kNullProcessHandle; |
| 110 #if defined(OS_WIN) |
| 111 // TODO(eroman): Remove after done investigating 40447. |
| 112 StackString stack_command_line(cmd_line->command_line_string()); |
| 113 // This line might crash, since it calls the string copy-constructor: |
| 114 StackString stack_program(cmd_line->program()); |
| 115 |
| 116 handle = sandbox::StartProcessWithAccess(cmd_line, exposed_dir); |
| 117 #elif defined(OS_POSIX) |
| 118 |
| 119 #if defined(OS_LINUX) |
| 120 if (use_zygote) { |
| 121 base::GlobalDescriptors::Mapping mapping; |
| 122 mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd)); |
| 123 const int crash_signal_fd = |
| 124 Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket(); |
| 125 if (crash_signal_fd >= 0) { |
| 126 mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal, |
| 127 crash_signal_fd)); |
| 128 } |
| 129 handle = Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping); |
| 130 } else |
| 131 // Fall through to the normal posix case below when we're not zygoting. |
| 132 #endif |
| 133 { |
| 134 base::file_handle_mapping_vector fds_to_map; |
| 135 fds_to_map.push_back(std::make_pair( |
| 136 ipcfd, |
| 137 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor)); |
| 138 |
| 139 #if defined(OS_LINUX) |
| 140 // On Linux, we need to add some extra file descriptors for crash handling |
| 141 // and the sandbox. |
| 142 bool is_renderer = |
| 143 cmd_line->GetSwitchValueASCII(switches::kProcessType) == |
| 144 switches::kRendererProcess; |
| 145 bool is_plugin = |
| 146 cmd_line->GetSwitchValueASCII(switches::kProcessType) == |
| 147 switches::kPluginProcess; |
| 148 |
| 149 if (is_renderer || is_plugin) { |
| 150 int crash_signal_fd; |
| 151 if (is_renderer) { |
| 152 crash_signal_fd = Singleton<RendererCrashHandlerHostLinux>()-> |
| 153 GetDeathSignalSocket(); |
| 154 } else { |
| 155 crash_signal_fd = Singleton<PluginCrashHandlerHostLinux>()-> |
| 156 GetDeathSignalSocket(); |
| 157 } |
| 158 if (crash_signal_fd >= 0) { |
| 159 fds_to_map.push_back(std::make_pair( |
| 160 crash_signal_fd, |
| 161 kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor)); |
| 162 } |
| 163 } |
| 164 if (is_renderer) { |
| 165 const int sandbox_fd = |
| 166 Singleton<RenderSandboxHostLinux>()->GetRendererSocket(); |
| 167 fds_to_map.push_back(std::make_pair( |
| 168 sandbox_fd, |
| 169 kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor)); |
| 170 } |
| 171 #endif // defined(OS_LINUX) |
| 172 |
| 173 // Actually launch the app. |
| 174 bool launched; |
| 175 #if defined(OS_MACOSX) |
| 176 task_t child_task; |
| 177 launched = base::LaunchAppAndGetTask( |
| 178 cmd_line->argv(), env, fds_to_map, false, &child_task, &handle); |
| 179 if (launched && child_task != MACH_PORT_NULL) { |
| 180 MachBroker::instance()->RegisterPid( |
| 181 handle, |
| 182 MachBroker::MachInfo().SetTask(child_task)); |
| 183 } |
| 184 #else |
| 185 launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map, |
| 186 /* wait= */false, &handle); |
| 187 #endif |
| 188 if (!launched) |
| 189 handle = base::kNullProcessHandle; |
| 190 } |
| 191 #endif // else defined(OS_POSIX) |
| 192 |
| 193 return handle; |
| 194 } |
| 195 |
| 196 void ChildProcessContext::EnsureProcessTerminated(base::ProcessHandle) { |
| 197 // On POSIX, we must additionally reap the child. |
| 198 #if defined(OS_POSIX) |
| 199 #if defined(OS_LINUX) |
| 200 if (zygote) { |
| 201 // If the renderer was created via a zygote, we have to proxy the reaping |
| 202 // through the zygote process. |
| 203 Singleton<ZygoteHost>()->EnsureProcessTerminated(handle); |
| 204 } else |
| 205 #endif // OS_LINUX |
| 206 { |
| 207 ProcessWatcher::EnsureProcessTerminated(handle); |
| 208 } |
| 209 #endif // OS_POSIX |
| 210 } |
| 211 |
| 212 bool ChildProcessContext::CheckProcessCrash(bool* child_exited, |
| 213 #if defined(OS_POSIX) |
| 214 bool use_zygote, |
| 215 #endif |
| 216 base::ProcessHandle handle) { |
| 217 #if defined(OS_LINUX) |
| 218 if (use_zygote) { |
| 219 return Singleton<ZygoteHost>()->DidProcessCrash(handle, child_exited); |
| 220 } else |
| 221 #endif |
| 222 { |
| 223 return base::DidProcessCrash(child_exited, handle); |
| 224 } |
| 225 } |
OLD | NEW |