| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/renderer/chrome_render_process_observer.h" | 5 #include "chrome/renderer/chrome_render_process_observer.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/metrics/field_trial.h" | 9 #include "base/metrics/field_trial.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFontCache.h" | 40 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFontCache.h" |
| 41 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 41 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| 42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRuntimeFeatures.h" | 42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRuntimeFeatures.h" |
| 43 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | 43 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
| 44 #include "v8/include/v8.h" | 44 #include "v8/include/v8.h" |
| 45 | 45 |
| 46 #if defined(OS_WIN) | 46 #if defined(OS_WIN) |
| 47 #include "base/win/iat_patch_function.h" | 47 #include "base/win/iat_patch_function.h" |
| 48 #endif | 48 #endif |
| 49 | 49 |
| 50 #if defined(OS_MACOSX) | |
| 51 #include "base/eintr_wrapper.h" | |
| 52 #include "chrome/app/breakpad_mac.h" | |
| 53 #endif | |
| 54 | |
| 55 using WebKit::WebCache; | 50 using WebKit::WebCache; |
| 56 using WebKit::WebCrossOriginPreflightResultCache; | 51 using WebKit::WebCrossOriginPreflightResultCache; |
| 57 using WebKit::WebFontCache; | 52 using WebKit::WebFontCache; |
| 58 using WebKit::WebRuntimeFeatures; | 53 using WebKit::WebRuntimeFeatures; |
| 59 | 54 |
| 60 namespace { | 55 namespace { |
| 61 | 56 |
| 62 static const unsigned int kCacheStatsDelayMS = 2000 /* milliseconds */; | 57 static const unsigned int kCacheStatsDelayMS = 2000 /* milliseconds */; |
| 63 | 58 |
| 64 class RendererResourceDelegate : public ResourceDispatcherDelegate { | 59 class RendererResourceDelegate : public ResourceDispatcherDelegate { |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 // processed (because that message loop is stuck in V8). | 178 // processed (because that message loop is stuck in V8). |
| 184 // | 179 // |
| 185 // One could make the browser SIGKILL the renderers, but that leaves open a | 180 // One could make the browser SIGKILL the renderers, but that leaves open a |
| 186 // large window where a browser failure (or a user, manually terminating | 181 // large window where a browser failure (or a user, manually terminating |
| 187 // the browser because "it's stuck") will leave behind a process eating all | 182 // the browser because "it's stuck") will leave behind a process eating all |
| 188 // the CPU. | 183 // the CPU. |
| 189 // | 184 // |
| 190 // So, we install a filter on the channel so that we can process this event | 185 // So, we install a filter on the channel so that we can process this event |
| 191 // here and kill the process. | 186 // here and kill the process. |
| 192 | 187 |
| 193 #if defined(OS_MACOSX) | |
| 194 // TODO(viettrungluu): crbug.com/28547: The following is needed, as a | |
| 195 // stopgap, to avoid leaking due to not releasing Breakpad properly. | |
| 196 // TODO(viettrungluu): Investigate why this is being called. | |
| 197 if (IsCrashReporterEnabled()) { | |
| 198 VLOG(1) << "Cleaning up Breakpad."; | |
| 199 DestructCrashReporter(); | |
| 200 } else { | |
| 201 VLOG(1) << "Breakpad not enabled; no clean-up needed."; | |
| 202 } | |
| 203 #endif // OS_MACOSX | |
| 204 | |
| 205 _exit(0); | 188 _exit(0); |
| 206 } | 189 } |
| 207 }; | 190 }; |
| 208 #endif // OS_POSIX | 191 #endif // OS_POSIX |
| 209 | 192 |
| 210 #if defined(OS_MACOSX) | |
| 211 // TODO(viettrungluu): crbug.com/28547: The following signal handling is needed, | |
| 212 // as a stopgap, to avoid leaking due to not releasing Breakpad properly. | |
| 213 // Without this problem, this could all be eliminated. Remove when Breakpad is | |
| 214 // fixed? | |
| 215 // TODO(viettrungluu): Code taken from browser_main.cc (with a bit of editing). | |
| 216 // The code should be properly shared (or this code should be eliminated). | |
| 217 int g_shutdown_pipe_write_fd = -1; | |
| 218 | |
| 219 void SIGTERMHandler(int signal) { | |
| 220 RAW_CHECK(signal == SIGTERM); | |
| 221 | |
| 222 // Reinstall the default handler. We had one shot at graceful shutdown. | |
| 223 struct sigaction action; | |
| 224 memset(&action, 0, sizeof(action)); | |
| 225 action.sa_handler = SIG_DFL; | |
| 226 CHECK(sigaction(signal, &action, NULL) == 0); | |
| 227 | |
| 228 RAW_CHECK(g_shutdown_pipe_write_fd != -1); | |
| 229 size_t bytes_written = 0; | |
| 230 do { | |
| 231 int rv = HANDLE_EINTR( | |
| 232 write(g_shutdown_pipe_write_fd, | |
| 233 reinterpret_cast<const char*>(&signal) + bytes_written, | |
| 234 sizeof(signal) - bytes_written)); | |
| 235 RAW_CHECK(rv >= 0); | |
| 236 bytes_written += rv; | |
| 237 } while (bytes_written < sizeof(signal)); | |
| 238 } | |
| 239 | |
| 240 class ShutdownDetector : public base::PlatformThread::Delegate { | |
| 241 public: | |
| 242 explicit ShutdownDetector(int shutdown_fd) : shutdown_fd_(shutdown_fd) { | |
| 243 CHECK(shutdown_fd_ != -1); | |
| 244 } | |
| 245 | |
| 246 virtual void ThreadMain() { | |
| 247 int signal; | |
| 248 size_t bytes_read = 0; | |
| 249 ssize_t ret; | |
| 250 do { | |
| 251 ret = HANDLE_EINTR( | |
| 252 read(shutdown_fd_, | |
| 253 reinterpret_cast<char*>(&signal) + bytes_read, | |
| 254 sizeof(signal) - bytes_read)); | |
| 255 if (ret < 0) { | |
| 256 NOTREACHED() << "Unexpected error: " << strerror(errno); | |
| 257 break; | |
| 258 } else if (ret == 0) { | |
| 259 NOTREACHED() << "Unexpected closure of shutdown pipe."; | |
| 260 break; | |
| 261 } | |
| 262 bytes_read += ret; | |
| 263 } while (bytes_read < sizeof(signal)); | |
| 264 | |
| 265 if (bytes_read == sizeof(signal)) | |
| 266 VLOG(1) << "Handling shutdown for signal " << signal << "."; | |
| 267 else | |
| 268 VLOG(1) << "Handling shutdown for unknown signal."; | |
| 269 | |
| 270 // Clean up Breakpad if necessary. | |
| 271 if (IsCrashReporterEnabled()) { | |
| 272 VLOG(1) << "Cleaning up Breakpad."; | |
| 273 DestructCrashReporter(); | |
| 274 } else { | |
| 275 VLOG(1) << "Breakpad not enabled; no clean-up needed."; | |
| 276 } | |
| 277 | |
| 278 // Something went seriously wrong, so get out. | |
| 279 if (bytes_read != sizeof(signal)) { | |
| 280 LOG(WARNING) << "Failed to get signal. Quitting ungracefully."; | |
| 281 _exit(1); | |
| 282 } | |
| 283 | |
| 284 // Re-raise the signal. | |
| 285 kill(getpid(), signal); | |
| 286 | |
| 287 // The signal may be handled on another thread. Give that a chance to | |
| 288 // happen. | |
| 289 sleep(3); | |
| 290 | |
| 291 // We really should be dead by now. For whatever reason, we're not. Exit | |
| 292 // immediately, with the exit status set to the signal number with bit 8 | |
| 293 // set. On the systems that we care about, this exit status is what is | |
| 294 // normally used to indicate an exit by this signal's default handler. | |
| 295 // This mechanism isn't a de jure standard, but even in the worst case, it | |
| 296 // should at least result in an immediate exit. | |
| 297 LOG(WARNING) << "Still here, exiting really ungracefully."; | |
| 298 _exit(signal | (1 << 7)); | |
| 299 } | |
| 300 | |
| 301 private: | |
| 302 const int shutdown_fd_; | |
| 303 | |
| 304 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); | |
| 305 }; | |
| 306 #endif // OS_MACOSX | |
| 307 | |
| 308 } // namespace | 193 } // namespace |
| 309 | 194 |
| 310 bool ChromeRenderProcessObserver::is_incognito_process_ = false; | 195 bool ChromeRenderProcessObserver::is_incognito_process_ = false; |
| 311 | 196 |
| 312 ChromeRenderProcessObserver::ChromeRenderProcessObserver( | 197 ChromeRenderProcessObserver::ChromeRenderProcessObserver( |
| 313 chrome::ChromeContentRendererClient* client) | 198 chrome::ChromeContentRendererClient* client) |
| 314 : client_(client) { | 199 : client_(client) { |
| 315 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 200 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 316 if (command_line.HasSwitch(switches::kEnableWatchdog)) { | 201 if (command_line.HasSwitch(switches::kEnableWatchdog)) { |
| 317 // TODO(JAR): Need to implement renderer IO msgloop watchdog. | 202 // TODO(JAR): Need to implement renderer IO msgloop watchdog. |
| 318 } | 203 } |
| 319 | 204 |
| 320 if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) { | 205 if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) { |
| 321 base::StatisticsRecorder::set_dump_on_exit(true); | 206 base::StatisticsRecorder::set_dump_on_exit(true); |
| 322 } | 207 } |
| 323 | 208 |
| 324 RenderThread* thread = RenderThread::current(); | 209 RenderThread* thread = RenderThread::current(); |
| 325 resource_delegate_.reset(new RendererResourceDelegate()); | 210 resource_delegate_.reset(new RendererResourceDelegate()); |
| 326 thread->resource_dispatcher()->set_delegate(resource_delegate_.get()); | 211 thread->resource_dispatcher()->set_delegate(resource_delegate_.get()); |
| 327 | 212 |
| 328 #if defined(OS_POSIX) | 213 #if defined(OS_POSIX) |
| 329 thread->AddFilter(new SuicideOnChannelErrorFilter()); | 214 thread->AddFilter(new SuicideOnChannelErrorFilter()); |
| 330 #endif | 215 #endif |
| 331 | 216 |
| 332 #if defined(OS_MACOSX) | |
| 333 // TODO(viettrungluu): Code taken from browser_main.cc. | |
| 334 int pipefd[2]; | |
| 335 int ret = pipe(pipefd); | |
| 336 if (ret < 0) { | |
| 337 PLOG(DFATAL) << "Failed to create pipe"; | |
| 338 } else { | |
| 339 int shutdown_pipe_read_fd = pipefd[0]; | |
| 340 g_shutdown_pipe_write_fd = pipefd[1]; | |
| 341 const size_t kShutdownDetectorThreadStackSize = 4096; | |
| 342 if (!base::PlatformThread::CreateNonJoinable( | |
| 343 kShutdownDetectorThreadStackSize, | |
| 344 new ShutdownDetector(shutdown_pipe_read_fd))) { | |
| 345 LOG(DFATAL) << "Failed to create shutdown detector task."; | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 // crbug.com/28547: When Breakpad is in use, handle SIGTERM to avoid leaking | |
| 350 // Mach ports. | |
| 351 struct sigaction action; | |
| 352 memset(&action, 0, sizeof(action)); | |
| 353 action.sa_handler = SIGTERMHandler; | |
| 354 CHECK(sigaction(SIGTERM, &action, NULL) == 0); | |
| 355 #endif | |
| 356 | |
| 357 // Configure modules that need access to resources. | 217 // Configure modules that need access to resources. |
| 358 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider); | 218 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider); |
| 359 | 219 |
| 360 #if defined(OS_WIN) | 220 #if defined(OS_WIN) |
| 361 // Need to patch a few functions for font loading to work correctly. | 221 // Need to patch a few functions for font loading to work correctly. |
| 362 FilePath pdf; | 222 FilePath pdf; |
| 363 if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) && | 223 if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) && |
| 364 file_util::PathExists(pdf)) { | 224 file_util::PathExists(pdf)) { |
| 365 g_iat_patch_createdca.Patch( | 225 g_iat_patch_createdca.Patch( |
| 366 pdf.value().c_str(), "gdi32.dll", "CreateDCA", CreateDCAPatch); | 226 pdf.value().c_str(), "gdi32.dll", "CreateDCA", CreateDCAPatch); |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 } | 402 } |
| 543 | 403 |
| 544 #if !defined(OS_MACOSX) && defined(USE_TCMALLOC) | 404 #if !defined(OS_MACOSX) && defined(USE_TCMALLOC) |
| 545 // Tell tcmalloc to release any free pages it's still holding. | 405 // Tell tcmalloc to release any free pages it's still holding. |
| 546 MallocExtension::instance()->ReleaseFreeMemory(); | 406 MallocExtension::instance()->ReleaseFreeMemory(); |
| 547 #endif | 407 #endif |
| 548 | 408 |
| 549 if (client_) | 409 if (client_) |
| 550 client_->OnPurgeMemory(); | 410 client_->OnPurgeMemory(); |
| 551 } | 411 } |
| OLD | NEW |