
We don't create it in production anymore for UI thread. This wasn't obvious, e.g. see the fix in https://crrev.com/c/2877684. Bug: 904556 Change-Id: I4e6eaeeafd6144c30c4822a11806dfa24e4363e4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2878894 Commit-Queue: John Abd-El-Malek <jam@chromium.org> Reviewed-by: Gabriel Charette <gab@chromium.org> Cr-Commit-Position: refs/heads/master@{#880433}
188 lines
6.2 KiB
C++
188 lines
6.2 KiB
C++
// Copyright (c) 2012 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 "content/browser/browser_process_io_thread.h"
|
|
|
|
#include "base/bind.h"
|
|
#include "base/callback_helpers.h"
|
|
#include "base/clang_profiling_buildflags.h"
|
|
#include "base/compiler_specific.h"
|
|
#include "base/debug/alias.h"
|
|
#include "base/metrics/histogram_macros.h"
|
|
#include "base/threading/hang_watcher.h"
|
|
#include "base/threading/thread_restrictions.h"
|
|
#include "base/trace_event/memory_dump_manager.h"
|
|
#include "build/chromeos_buildflags.h"
|
|
#include "content/browser/browser_child_process_host_impl.h"
|
|
#include "content/browser/browser_thread_impl.h"
|
|
#include "content/browser/notification_service_impl.h"
|
|
#include "content/browser/utility_process_host.h"
|
|
#include "content/common/child_process_host_impl.h"
|
|
#include "content/public/browser/browser_child_process_host_iterator.h"
|
|
#include "content/public/common/content_features.h"
|
|
#include "content/public/common/process_type.h"
|
|
#include "net/url_request/url_fetcher.h"
|
|
#include "services/network/public/mojom/network_service.mojom.h"
|
|
|
|
#if defined(OS_ANDROID)
|
|
#include "base/android/jni_android.h"
|
|
#endif
|
|
|
|
#if defined(OS_WIN)
|
|
#include "base/win/scoped_com_initializer.h"
|
|
#endif
|
|
|
|
namespace content {
|
|
|
|
BrowserProcessIOThread::BrowserProcessIOThread()
|
|
: base::Thread(BrowserThreadImpl::GetThreadName(BrowserThread::IO)) {
|
|
// Not bound to creation thread.
|
|
DETACH_FROM_THREAD(browser_thread_checker_);
|
|
}
|
|
|
|
BrowserProcessIOThread::~BrowserProcessIOThread() {
|
|
Stop();
|
|
}
|
|
|
|
void BrowserProcessIOThread::RegisterAsBrowserThread() {
|
|
DCHECK(IsRunning());
|
|
|
|
DCHECK(!browser_thread_);
|
|
browser_thread_.reset(
|
|
new BrowserThreadImpl(BrowserThread::IO, task_runner()));
|
|
|
|
// Unretained(this) is safe as |this| outlives its underlying thread.
|
|
task_runner()->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(
|
|
&BrowserProcessIOThread::CompleteInitializationOnBrowserThread,
|
|
Unretained(this)));
|
|
}
|
|
|
|
void BrowserProcessIOThread::AllowBlockingForTesting() {
|
|
DCHECK(!IsRunning());
|
|
is_blocking_allowed_for_testing_ = true;
|
|
}
|
|
|
|
void BrowserProcessIOThread::Init() {
|
|
DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
|
|
|
|
#if defined(OS_WIN)
|
|
com_initializer_ = std::make_unique<base::win::ScopedCOMInitializer>();
|
|
#endif
|
|
|
|
if (!is_blocking_allowed_for_testing_) {
|
|
base::DisallowUnresponsiveTasks();
|
|
}
|
|
}
|
|
|
|
void BrowserProcessIOThread::Run(base::RunLoop* run_loop) {
|
|
DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
|
|
|
|
#if defined(OS_ANDROID)
|
|
// Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
|
|
// Though it may create unnecessary VM thread objects, keeping thread name
|
|
// gives more benefit in debugging in the platform.
|
|
if (!thread_name().empty()) {
|
|
base::android::AttachCurrentThreadWithName(thread_name());
|
|
}
|
|
#endif
|
|
|
|
IOThreadRun(run_loop);
|
|
}
|
|
|
|
void BrowserProcessIOThread::CleanUp() {
|
|
DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
|
|
|
|
// Run extra cleanup if this thread represents BrowserThread::IO.
|
|
if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
|
|
IOThreadCleanUp();
|
|
|
|
if (!base::FeatureList::IsEnabled(features::kProcessHostOnUI))
|
|
ProcessHostCleanUp();
|
|
}
|
|
|
|
notification_service_.reset();
|
|
|
|
#if defined(OS_WIN)
|
|
com_initializer_.reset();
|
|
#endif
|
|
}
|
|
|
|
void BrowserProcessIOThread::CompleteInitializationOnBrowserThread() {
|
|
DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
|
|
|
|
notification_service_ = std::make_unique<NotificationServiceImpl>();
|
|
}
|
|
|
|
void BrowserProcessIOThread::IOThreadRun(base::RunLoop* run_loop) {
|
|
// Register the IO thread for hang watching before it starts running and set
|
|
// up a closure to automatically unregister it when Run() returns.
|
|
base::ScopedClosureRunner unregister_thread_closure;
|
|
if (base::HangWatcher::IsIOThreadHangWatchingEnabled()) {
|
|
unregister_thread_closure = base::HangWatcher::RegisterThread(
|
|
base::HangWatcher::ThreadType::kIOThread);
|
|
}
|
|
|
|
Thread::Run(run_loop);
|
|
|
|
// Inhibit tail calls of Run and inhibit code folding.
|
|
const int line_number = __LINE__;
|
|
base::debug::Alias(&line_number);
|
|
}
|
|
|
|
void BrowserProcessIOThread::IOThreadCleanUp() {
|
|
DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
|
|
|
|
// Kill all things that might be holding onto
|
|
// net::URLRequest/net::URLRequestContexts.
|
|
|
|
// Destroy all URLRequests started by URLFetchers.
|
|
net::URLFetcher::CancelAll();
|
|
}
|
|
|
|
void BrowserProcessIOThread::ProcessHostCleanUp() {
|
|
for (BrowserChildProcessHostIterator it(PROCESS_TYPE_UTILITY); !it.Done();
|
|
++it) {
|
|
if (it.GetDelegate()->GetServiceName() ==
|
|
network::mojom::NetworkService::Name_) {
|
|
// This ensures that cookies and cache are flushed to disk on shutdown.
|
|
// https://crbug.com/841001
|
|
#if BUILDFLAG(CLANG_PROFILING)
|
|
// On profiling build, browser_tests runs 10x slower.
|
|
const int kMaxSecondsToWaitForNetworkProcess = 100;
|
|
#elif BUILDFLAG(IS_CHROMEOS_ASH)
|
|
// ChromeOS will kill the browser process if it doesn't shut down within
|
|
// 3 seconds, so make sure we wait for less than that.
|
|
const int kMaxSecondsToWaitForNetworkProcess = 1;
|
|
#else
|
|
const int kMaxSecondsToWaitForNetworkProcess = 10;
|
|
#endif
|
|
|
|
ChildProcessHostImpl* child_process =
|
|
static_cast<ChildProcessHostImpl*>(it.GetHost());
|
|
auto& process = child_process->peer_process();
|
|
if (!process.IsValid())
|
|
continue;
|
|
base::ScopedAllowBaseSyncPrimitives scoped_allow_base_sync_primitives;
|
|
const base::TimeTicks start_time = base::TimeTicks::Now();
|
|
process.WaitForExitWithTimeout(
|
|
base::TimeDelta::FromSeconds(kMaxSecondsToWaitForNetworkProcess),
|
|
nullptr);
|
|
// Record time spent for the method call.
|
|
base::TimeDelta network_wait_time = base::TimeTicks::Now() - start_time;
|
|
UMA_HISTOGRAM_TIMES("NetworkService.ShutdownTime", network_wait_time);
|
|
DVLOG(1) << "Waited " << network_wait_time.InMilliseconds()
|
|
<< " ms for network service";
|
|
}
|
|
}
|
|
|
|
// If any child processes are still running, terminate them and
|
|
// and delete the BrowserChildProcessHost instances to release whatever
|
|
// IO thread only resources they are referencing.
|
|
BrowserChildProcessHostImpl::TerminateAll();
|
|
}
|
|
|
|
} // namespace content
|