| Index: chrome/installer/setup/setup_singleton.cc
|
| diff --git a/chrome/installer/setup/setup_singleton.cc b/chrome/installer/setup/setup_singleton.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..de73e9f60c1f258f0e21f60cce659e25a028685e
|
| --- /dev/null
|
| +++ b/chrome/installer/setup/setup_singleton.cc
|
| @@ -0,0 +1,138 @@
|
| +// Copyright 2016 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 "chrome/installer/setup/setup_singleton.h"
|
| +
|
| +#include "base/files/file_path.h"
|
| +#include "base/logging.h"
|
| +#include "base/metrics/histogram_macros.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/time/time.h"
|
| +#include "chrome/installer/util/installation_state.h"
|
| +#include "chrome/installer/util/installer_state.h"
|
| +
|
| +namespace installer {
|
| +
|
| +namespace {
|
| +
|
| +enum SetupSingletonAcquisitionResult {
|
| + // The setup singleton was acquired successfully.
|
| + SETUP_SINGLETON_ACQUISITION_SUCCESS = 0,
|
| + // Acquisition of the exit event mutex timed out.
|
| + SETUP_SINGLETON_ACQUISITION_EXIT_EVENT_MUTEX_TIMEOUT = 1,
|
| + // Acquisition of the setup mutex timed out.
|
| + SETUP_SINGLETON_ACQUISITION_SETUP_MUTEX_TIMEOUT = 2,
|
| + SETUP_SINGLETON_ACQUISITION_RESULT_COUNT,
|
| +};
|
| +
|
| +void RecordSetupSingletonAcquisitionResultHistogram(
|
| + SetupSingletonAcquisitionResult result) {
|
| + UMA_HISTOGRAM_ENUMERATION("Setup.Install.SingletonAcquisitionResult", result,
|
| + SETUP_SINGLETON_ACQUISITION_RESULT_COUNT);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +std::unique_ptr<SetupSingleton> SetupSingleton::Acquire(
|
| + const base::CommandLine& command_line,
|
| + const MasterPreferences& master_preferences,
|
| + InstallationState* original_state,
|
| + InstallerState* installer_state) {
|
| + DCHECK(original_state);
|
| + DCHECK(installer_state);
|
| +
|
| + const base::string16 sync_primitive_name_suffix(
|
| + base::SizeTToString16(std::hash<base::FilePath::StringType>()(
|
| + installer_state->target_path().value())));
|
| +
|
| + std::unique_ptr<SetupSingleton> setup_singleton(
|
| + new SetupSingleton(sync_primitive_name_suffix));
|
| +
|
| + {
|
| + // Acquire a mutex to ensure that a single call to SetupSingleton::Acquire()
|
| + // signals |exit_event_| and waits for |setup_mutex_| to be released at a
|
| + // time.
|
| + base::win::ScopedHandle exit_event_mutex(::CreateMutex(
|
| + nullptr, FALSE,
|
| + (L"Global\\ChromeSetupExitEventMutex_" + sync_primitive_name_suffix)
|
| + .c_str()));
|
| + DCHECK(exit_event_mutex.IsValid());
|
| + ScopedHoldMutex scoped_hold_exit_event_mutex;
|
| + if (!scoped_hold_exit_event_mutex.Acquire(exit_event_mutex.Get())) {
|
| + RecordSetupSingletonAcquisitionResultHistogram(
|
| + SETUP_SINGLETON_ACQUISITION_EXIT_EVENT_MUTEX_TIMEOUT);
|
| + return nullptr;
|
| + }
|
| +
|
| + // Signal |exit_event_|. This causes any call to WaitForInterrupt() on a
|
| + // SetupSingleton bound to the same Chrome installation to return
|
| + // immediately.
|
| + setup_singleton->exit_event_.Signal();
|
| +
|
| + // Acquire |setup_mutex_|.
|
| + if (!setup_singleton->scoped_hold_setup_mutex_.Acquire(
|
| + setup_singleton->setup_mutex_.Get())) {
|
| + RecordSetupSingletonAcquisitionResultHistogram(
|
| + SETUP_SINGLETON_ACQUISITION_SETUP_MUTEX_TIMEOUT);
|
| + return nullptr;
|
| + }
|
| + setup_singleton->exit_event_.Reset();
|
| + }
|
| +
|
| + // Update |original_state| and |installer_state|.
|
| + original_state->Initialize();
|
| + installer_state->Initialize(command_line, master_preferences,
|
| + *original_state);
|
| +
|
| + RecordSetupSingletonAcquisitionResultHistogram(
|
| + SETUP_SINGLETON_ACQUISITION_SUCCESS);
|
| + return setup_singleton;
|
| +}
|
| +
|
| +SetupSingleton::~SetupSingleton() = default;
|
| +
|
| +bool SetupSingleton::WaitForInterrupt(const base::TimeDelta& max_time) {
|
| + const bool exit_event_signaled = exit_event_.TimedWait(max_time);
|
| + return exit_event_signaled;
|
| +}
|
| +
|
| +SetupSingleton::ScopedHoldMutex::ScopedHoldMutex() = default;
|
| +
|
| +SetupSingleton::ScopedHoldMutex::~ScopedHoldMutex() {
|
| + if (mutex_ != INVALID_HANDLE_VALUE)
|
| + ::ReleaseMutex(mutex_);
|
| +}
|
| +
|
| +bool SetupSingleton::ScopedHoldMutex::Acquire(HANDLE mutex) {
|
| + DCHECK_NE(INVALID_HANDLE_VALUE, mutex);
|
| + DCHECK_EQ(INVALID_HANDLE_VALUE, mutex_);
|
| +
|
| + const DWORD wait_return_value = ::WaitForSingleObject(
|
| + mutex,
|
| + static_cast<DWORD>(base::TimeDelta::FromSeconds(5).InMilliseconds()));
|
| + if (wait_return_value == WAIT_ABANDONED ||
|
| + wait_return_value == WAIT_OBJECT_0) {
|
| + mutex_ = mutex;
|
| + return true;
|
| + }
|
| +
|
| + DPCHECK(wait_return_value != WAIT_FAILED);
|
| + return false;
|
| +}
|
| +
|
| +SetupSingleton::SetupSingleton(const base::string16& sync_primitive_name_suffix)
|
| + : setup_mutex_(::CreateMutex(
|
| + nullptr,
|
| + FALSE,
|
| + (L"Global\\ChromeSetupMutex_" + sync_primitive_name_suffix).c_str())),
|
| + exit_event_(base::win::ScopedHandle(::CreateEvent(
|
| + nullptr,
|
| + TRUE,
|
| + FALSE,
|
| + (L"Global\\ChromeSetupExitEvent_" + sync_primitive_name_suffix)
|
| + .c_str()))) {
|
| + DCHECK(setup_mutex_.IsValid());
|
| +}
|
| +
|
| +} // namespace installer
|
|
|