// Copyright 2012 The Chromium Authors // 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/clang_profiling_buildflags.h" #include "base/compiler_specific.h" #include "base/debug/alias.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/threading/hang_watcher.h" #include "base/threading/thread_restrictions.h" #include "base/trace_event/memory_dump_manager.h" #include "build/build_config.h" #include "content/browser/browser_child_process_host_impl.h" #include "content/browser/browser_thread_impl.h" #include "content/browser/child_process_host_impl.h" #include "content/browser/service_host/utility_process_host.h" #include "content/public/browser/browser_child_process_host_iterator.h" #include "content/public/common/process_type.h" #include "services/network/public/mojom/network_service.mojom.h" #if BUILDFLAG(IS_ANDROID) #include "base/android/jni_android.h" #endif #if BUILDFLAG(IS_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())); } void BrowserProcessIOThread::AllowBlockingForTesting() { DCHECK(!IsRunning()); is_blocking_allowed_for_testing_ = true; } void BrowserProcessIOThread::Init() { DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_); #if BUILDFLAG(IS_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 BUILDFLAG(IS_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_); #if BUILDFLAG(IS_WIN) com_initializer_.reset(); #endif } 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); NO_CODE_FOLDING(); } 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) // 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->GetPeerProcess(); if (!process.IsValid()) continue; base::ScopedAllowBaseSyncPrimitives scoped_allow_base_sync_primitives; const base::TimeTicks start_time = base::TimeTicks::Now(); process.WaitForExitWithTimeout( base::Seconds(kMaxSecondsToWaitForNetworkProcess), nullptr); // Record time spent for the method call. base::TimeDelta network_wait_time = base::TimeTicks::Now() - start_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