blob: 66f30fc80530e371e7013a6cc9e215db55496b69 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chrome_process_singleton.h"
#include <utility>
#include "build/build_config.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/compiler_specific.h"
#include "base/metrics/histogram_functions.h"
#include "chrome/common/chrome_features.h"
#include "components/app_launch_prefetch/app_launch_prefetch.h"
#endif
namespace {
ChromeProcessSingleton* g_chrome_process_singleton_ = nullptr;
} // namespace
ChromeProcessSingleton::ChromeProcessSingleton(
const base::FilePath& user_data_dir)
: startup_lock_(
base::BindRepeating(&ChromeProcessSingleton::NotificationCallback,
base::Unretained(this))),
process_singleton_(user_data_dir,
startup_lock_.AsNotificationCallback()) {}
ChromeProcessSingleton::~ChromeProcessSingleton() = default;
ProcessSingleton::NotifyResult
ChromeProcessSingleton::NotifyOtherProcessOrCreate() {
CHECK(!is_singleton_instance_);
ProcessSingleton::NotifyResult result =
process_singleton_.NotifyOtherProcessOrCreate();
if (result == ProcessSingleton::PROCESS_NONE) {
is_singleton_instance_ = true;
}
return result;
}
void ChromeProcessSingleton::StartWatching() {
process_singleton_.StartWatching();
}
void ChromeProcessSingleton::Cleanup() {
if (is_singleton_instance_) {
process_singleton_.Cleanup();
}
}
void ChromeProcessSingleton::Unlock(
const ProcessSingleton::NotificationCallback& notification_callback) {
notification_callback_ = notification_callback;
startup_lock_.Unlock();
}
#if BUILDFLAG(IS_WIN)
void ChromeProcessSingleton::InitializeFeatures() {
// On Windows, App Launch Prefetch (ALPF) will monitor the disk accesses done
// by processes launched, and load the resources used into memory before the
// process needs them, if possible. Different Chrome process types use
// different resources, and this is signaled to ALPF via the command line:
// passing "/prefetch:N" on the command line with different numbers causes
// ALPF to treat two launches placed in different buckets as separarate
// applications for its purposes.
//
// Short lived browser processes occur on notification and rendezvous, both
// cases where nearly nothing will be used from disk, and which are not
// launched with `/prefetch`, and are thus considered "browser" processes
// according to ALPF. This may be polluting the ALPF cache.
//
// The `::ProcessOverrideSubsequentPrefetchParameter` process information
// attribute will change the behavior of ALPF to explicitly consider
// subsequent launches while this singleton process is running (rendezvous,
// toast) of Chrome which do not specify a prefetch bucket as if they had
// specified the `kCatchAll` bucket.
//
// It is expected that this will overall improve the behavior of ALPF on
// Windows, which should decrease startup time for ordinary browser processes.
if (is_singleton_instance_ &&
(UNSAFE_TODO(wcsstr(::GetCommandLineW(), L"/prefetch:")) == nullptr) &&
base::FeatureList::IsEnabled(features::kOverridePrefetchOnSingleton)) {
OVERRIDE_PREFETCH_PARAMETER prefetch_parameter = {};
prefetch_parameter.Value = app_launch_prefetch::GetPrefetchBucket(
app_launch_prefetch::SubprocessType::kCatchAll);
// This is not fatal because it is an optimization and has no bearing on the
// functionality of the browser. See crbug.com/380088804 for details. It has
// been seen that occasionally (in CQ), this call fails with
// ERROR_INTERNAL_ERROR.
base::UmaHistogramSparse(
"Startup.PrefetchOverrideErrorCode",
::SetProcessInformation(::GetCurrentProcess(),
::ProcessOverrideSubsequentPrefetchParameter,
&prefetch_parameter, sizeof(prefetch_parameter))
? ERROR_SUCCESS
: ::GetLastError());
}
}
#endif
// static
void ChromeProcessSingleton::CreateInstance(
const base::FilePath& user_data_dir) {
DCHECK(!g_chrome_process_singleton_);
DCHECK(!user_data_dir.empty());
g_chrome_process_singleton_ = new ChromeProcessSingleton(user_data_dir);
}
// static
void ChromeProcessSingleton::DeleteInstance() {
if (g_chrome_process_singleton_) {
delete g_chrome_process_singleton_;
g_chrome_process_singleton_ = nullptr;
}
}
// static
ChromeProcessSingleton* ChromeProcessSingleton::GetInstance() {
CHECK(g_chrome_process_singleton_);
return g_chrome_process_singleton_;
}
// static
bool ChromeProcessSingleton::IsSingletonInstance() {
return g_chrome_process_singleton_ &&
g_chrome_process_singleton_->is_singleton_instance_;
}
bool ChromeProcessSingleton::NotificationCallback(
base::CommandLine command_line,
const base::FilePath& current_directory) {
DCHECK(notification_callback_);
return notification_callback_.Run(std::move(command_line), current_directory);
}