| Index: chrome/browser/shell_integration.cc
|
| diff --git a/chrome/browser/shell_integration.cc b/chrome/browser/shell_integration.cc
|
| index 25e8ec7c55a6a087273821b26f6a3be7c7bb0be8..d8c5b8dcf38352aab3c7937c875c333fd463e3f6 100644
|
| --- a/chrome/browser/shell_integration.cc
|
| +++ b/chrome/browser/shell_integration.cc
|
| @@ -7,10 +7,12 @@
|
| #include "base/bind.h"
|
| #include "base/command_line.h"
|
| #include "base/files/file_util.h"
|
| +#include "base/metrics/histogram_macros.h"
|
| #include "base/prefs/pref_service.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/threading/thread_restrictions.h"
|
| +#include "base/timer/timer.h"
|
| #include "chrome/browser/policy/policy_path_parser.h"
|
| #include "chrome/common/chrome_paths.h"
|
| #include "chrome/common/chrome_switches.h"
|
| @@ -42,6 +44,11 @@ bool ShellIntegration::SetAsDefaultBrowserInteractive() {
|
| }
|
|
|
| // static
|
| +bool ShellIntegration::IsSetAsDefaultAsynchronous() {
|
| + return false;
|
| +}
|
| +
|
| +// static
|
| bool ShellIntegration::SetAsDefaultProtocolClientInteractive(
|
| const std::string& protocol) {
|
| return false;
|
| @@ -53,7 +60,11 @@ ShellIntegration::DefaultWebClientSetPermission
|
| ShellIntegration::CanSetAsDefaultProtocolClient() {
|
| // Allowed as long as the browser can become the operating system default
|
| // browser.
|
| - return CanSetAsDefaultBrowser();
|
| + DefaultWebClientSetPermission permission = CanSetAsDefaultBrowser();
|
| +
|
| + // Set as default asynchronous is only supported for default web browser.
|
| + return (permission == SET_DEFAULT_ASYNCHRONOUS) ? SET_DEFAULT_INTERACTIVE
|
| + : permission;
|
| }
|
|
|
| #if !defined(OS_WIN)
|
| @@ -162,51 +173,67 @@ bool ShellIntegration::DefaultWebClientObserver::
|
|
|
| ShellIntegration::DefaultWebClientWorker::DefaultWebClientWorker(
|
| DefaultWebClientObserver* observer)
|
| - : observer_(observer) {
|
| -}
|
| + : observer_(observer) {}
|
|
|
| void ShellIntegration::DefaultWebClientWorker::StartCheckIsDefault() {
|
| if (observer_) {
|
| observer_->SetDefaultWebClientUIState(STATE_PROCESSING);
|
| BrowserThread::PostTask(
|
| BrowserThread::FILE, FROM_HERE,
|
| - base::Bind(
|
| - &DefaultWebClientWorker::ExecuteCheckIsDefault, this));
|
| + base::Bind(&DefaultWebClientWorker::CheckIsDefault, this));
|
| }
|
| }
|
|
|
| void ShellIntegration::DefaultWebClientWorker::StartSetAsDefault() {
|
| + // Cancel the already running process if another start is requested.
|
| + if (set_as_default_in_progress_) {
|
| + if (set_as_default_initialized_) {
|
| + FinalizeSetAsDefault();
|
| + set_as_default_initialized_ = false;
|
| + }
|
| +
|
| + ReportAttemptResult(AttemptResult::RETRY);
|
| + }
|
| +
|
| + set_as_default_in_progress_ = true;
|
| bool interactive_permitted = false;
|
| if (observer_) {
|
| observer_->SetDefaultWebClientUIState(STATE_PROCESSING);
|
| interactive_permitted = observer_->IsInteractiveSetDefaultPermitted();
|
| +
|
| + // The initialization is only useful when there is an observer.
|
| + set_as_default_initialized_ = InitializeSetAsDefault();
|
| }
|
| - BrowserThread::PostTask(
|
| - BrowserThread::FILE, FROM_HERE,
|
| - base::Bind(&DefaultWebClientWorker::ExecuteSetAsDefault, this,
|
| - interactive_permitted));
|
| +
|
| + // Remember the start time.
|
| + start_time_ = base::TimeTicks::Now();
|
| +
|
| + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
| + base::Bind(&DefaultWebClientWorker::SetAsDefault,
|
| + this, interactive_permitted));
|
| }
|
|
|
| void ShellIntegration::DefaultWebClientWorker::ObserverDestroyed() {
|
| // Our associated view has gone away, so we shouldn't call back to it if
|
| // our worker thread returns after the view is dead.
|
| DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - observer_ = NULL;
|
| + observer_ = nullptr;
|
| +
|
| + if (set_as_default_initialized_) {
|
| + FinalizeSetAsDefault();
|
| + set_as_default_initialized_ = false;
|
| + }
|
| +
|
| + if (set_as_default_in_progress_)
|
| + ReportAttemptResult(AttemptResult::ABANDONED);
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| // DefaultWebClientWorker, private:
|
|
|
| -void ShellIntegration::DefaultWebClientWorker::ExecuteCheckIsDefault() {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::FILE);
|
| - DefaultWebClientState state = CheckIsDefault();
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(
|
| - &DefaultWebClientWorker::CompleteCheckIsDefault, this, state));
|
| -}
|
| +ShellIntegration::DefaultWebClientWorker::~DefaultWebClientWorker() {}
|
|
|
| -void ShellIntegration::DefaultWebClientWorker::CompleteCheckIsDefault(
|
| +void ShellIntegration::DefaultWebClientWorker::OnCheckIsDefaultComplete(
|
| DefaultWebClientState state) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| UpdateUI(state);
|
| @@ -214,29 +241,89 @@ void ShellIntegration::DefaultWebClientWorker::CompleteCheckIsDefault(
|
| // if we own it.
|
| if (observer_ && observer_->IsOwnedByWorker()) {
|
| delete observer_;
|
| - observer_ = NULL;
|
| + observer_ = nullptr;
|
| }
|
| }
|
|
|
| -void ShellIntegration::DefaultWebClientWorker::ExecuteSetAsDefault(
|
| - bool interactive_permitted) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::FILE);
|
| +void ShellIntegration::DefaultWebClientWorker::OnSetAsDefaultAttemptComplete(
|
| + AttemptResult result) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| + // Hold on to a reference because if this was called via the default browser
|
| + // callback in StartupBrowserCreator, clearing the callback in
|
| + // FinalizeSetAsDefault would otherwise remove the last reference and delete
|
| + // us in the middle of this function.
|
| + scoped_refptr<DefaultWebClientWorker> scoped_ref(this);
|
| +
|
| + if (set_as_default_in_progress_) {
|
| + set_as_default_in_progress_ = false;
|
| +
|
| + if (set_as_default_initialized_) {
|
| + FinalizeSetAsDefault();
|
| + set_as_default_initialized_ = false;
|
| + }
|
| + if (observer_) {
|
| + bool succeeded = result == AttemptResult::SUCCESS ||
|
| + result == AttemptResult::ALREADY_DEFAULT;
|
| + observer_->OnSetAsDefaultConcluded(succeeded);
|
| + }
|
|
|
| - bool result = SetAsDefault(interactive_permitted);
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&DefaultWebClientWorker::CompleteSetAsDefault, this, result));
|
| + ReportAttemptResult(result);
|
| +
|
| + // Start the default browser check which will notify the observer as to
|
| + // whether Chrome is really the default browser. This is needed because
|
| + // detecting that the process was successful is not 100% sure.
|
| + // For example, on Windows 10+, the user might have unchecked the "Always
|
| + // use this app" checkbox which can't be detected.
|
| + StartCheckIsDefault();
|
| + }
|
| }
|
|
|
| -void ShellIntegration::DefaultWebClientWorker::CompleteSetAsDefault(
|
| - bool succeeded) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - // First tell the observer what the SetAsDefault call has returned.
|
| - if (observer_)
|
| - observer_->OnSetAsDefaultConcluded(succeeded);
|
| - // Set as default completed, check again to make sure it stuck...
|
| - StartCheckIsDefault();
|
| +void ShellIntegration::DefaultWebClientWorker::ReportAttemptResult(
|
| + AttemptResult result) {
|
| + if (!ShouldReportAttemptResults())
|
| + return;
|
| +
|
| + UMA_HISTOGRAM_ENUMERATION("DefaultBrowser.AsyncSetAsDefault.Result", result,
|
| + AttemptResult::NUM_ATTEMPT_RESULT_TYPES);
|
| +
|
| + switch (result) {
|
| + case SUCCESS:
|
| + UMA_HISTOGRAM_MEDIUM_TIMES(
|
| + "DefaultBrowser.AsyncSetAsDefault.Duration_Success",
|
| + base::TimeTicks::Now() - start_time_);
|
| + break;
|
| + case FAILURE:
|
| + UMA_HISTOGRAM_MEDIUM_TIMES(
|
| + "DefaultBrowser.AsyncSetAsDefault.Duration_Failure",
|
| + base::TimeTicks::Now() - start_time_);
|
| + break;
|
| + case ABANDONED:
|
| + UMA_HISTOGRAM_MEDIUM_TIMES(
|
| + "DefaultBrowser.AsyncSetAsDefault.Duration_Abandoned",
|
| + base::TimeTicks::Now() - start_time_);
|
| + break;
|
| + case RETRY:
|
| + UMA_HISTOGRAM_MEDIUM_TIMES(
|
| + "DefaultBrowser.AsyncSetAsDefault.Duration_Retry",
|
| + base::TimeTicks::Now() - start_time_);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| +}
|
| +
|
| +bool ShellIntegration::DefaultWebClientWorker::InitializeSetAsDefault() {
|
| + return true;
|
| +}
|
| +
|
| +void ShellIntegration::DefaultWebClientWorker::FinalizeSetAsDefault() {}
|
| +
|
| +#if !defined(OS_WIN)
|
| +// static
|
| +bool ShellIntegration::DefaultWebClientWorker::ShouldReportAttemptResults() {
|
| + return false;
|
| }
|
| +#endif // !defined(OS_WIN)
|
|
|
| void ShellIntegration::DefaultWebClientWorker::UpdateUI(
|
| DefaultWebClientState state) {
|
| @@ -266,30 +353,59 @@ ShellIntegration::DefaultBrowserWorker::DefaultBrowserWorker(
|
| : DefaultWebClientWorker(observer) {
|
| }
|
|
|
| +ShellIntegration::DefaultBrowserWorker::~DefaultBrowserWorker() {}
|
| +
|
| ///////////////////////////////////////////////////////////////////////////////
|
| // DefaultBrowserWorker, private:
|
|
|
| -ShellIntegration::DefaultWebClientState
|
| -ShellIntegration::DefaultBrowserWorker::CheckIsDefault() {
|
| - return ShellIntegration::GetDefaultBrowser();
|
| +void ShellIntegration::DefaultBrowserWorker::CheckIsDefault() {
|
| + DefaultWebClientState state = GetDefaultBrowser();
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&DefaultBrowserWorker::OnCheckIsDefaultComplete, this, state));
|
| }
|
|
|
| -bool ShellIntegration::DefaultBrowserWorker::SetAsDefault(
|
| +void ShellIntegration::DefaultBrowserWorker::SetAsDefault(
|
| bool interactive_permitted) {
|
| - bool result = false;
|
| - switch (ShellIntegration::CanSetAsDefaultBrowser()) {
|
| - case ShellIntegration::SET_DEFAULT_UNATTENDED:
|
| - result = ShellIntegration::SetAsDefaultBrowser();
|
| + AttemptResult result = AttemptResult::FAILURE;
|
| + switch (CanSetAsDefaultBrowser()) {
|
| + case SET_DEFAULT_NOT_ALLOWED:
|
| + NOTREACHED();
|
| break;
|
| - case ShellIntegration::SET_DEFAULT_INTERACTIVE:
|
| - if (interactive_permitted)
|
| - result = ShellIntegration::SetAsDefaultBrowserInteractive();
|
| + case SET_DEFAULT_UNATTENDED:
|
| + if (SetAsDefaultBrowser())
|
| + result = AttemptResult::SUCCESS;
|
| break;
|
| - default:
|
| + case SET_DEFAULT_INTERACTIVE:
|
| + if (interactive_permitted && SetAsDefaultBrowserInteractive())
|
| + result = AttemptResult::SUCCESS;
|
| + break;
|
| + case SET_DEFAULT_ASYNCHRONOUS:
|
| +#if defined(OS_WIN)
|
| + if (!interactive_permitted)
|
| + break;
|
| + if (GetDefaultBrowser() == IS_DEFAULT) {
|
| + // Don't start the asynchronous operation since it could result in
|
| + // losing the default browser status.
|
| + result = AttemptResult::ALREADY_DEFAULT;
|
| + break;
|
| + }
|
| + // This function will cause OnSetAsDefaultAttemptComplete() to be called
|
| + // asynchronously via a filter established in InitializeSetAsDefault().
|
| + if (!SetAsDefaultBrowserAsynchronous()) {
|
| + result = AttemptResult::LAUNCH_FAILURE;
|
| + break;
|
| + }
|
| + return;
|
| +#else
|
| NOTREACHED();
|
| + break;
|
| +#endif
|
| }
|
| -
|
| - return result;
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&DefaultBrowserWorker::OnSetAsDefaultAttemptComplete, this,
|
| + result));
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| @@ -305,28 +421,39 @@ ShellIntegration::DefaultProtocolClientWorker::DefaultProtocolClientWorker(
|
| ///////////////////////////////////////////////////////////////////////////////
|
| // DefaultProtocolClientWorker, private:
|
|
|
| -ShellIntegration::DefaultWebClientState
|
| -ShellIntegration::DefaultProtocolClientWorker::CheckIsDefault() {
|
| - return ShellIntegration::IsDefaultProtocolClient(protocol_);
|
| +ShellIntegration::DefaultProtocolClientWorker::~DefaultProtocolClientWorker() {}
|
| +
|
| +void ShellIntegration::DefaultProtocolClientWorker::CheckIsDefault() {
|
| + DefaultWebClientState state = IsDefaultProtocolClient(protocol_);
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&DefaultProtocolClientWorker::OnCheckIsDefaultComplete, this,
|
| + state));
|
| }
|
|
|
| -bool ShellIntegration::DefaultProtocolClientWorker::SetAsDefault(
|
| +void ShellIntegration::DefaultProtocolClientWorker::SetAsDefault(
|
| bool interactive_permitted) {
|
| - bool result = false;
|
| - switch (ShellIntegration::CanSetAsDefaultProtocolClient()) {
|
| - case ShellIntegration::SET_DEFAULT_NOT_ALLOWED:
|
| - result = false;
|
| + AttemptResult result = AttemptResult::FAILURE;
|
| + switch (CanSetAsDefaultProtocolClient()) {
|
| + case SET_DEFAULT_NOT_ALLOWED:
|
| + // Not allowed, do nothing.
|
| break;
|
| - case ShellIntegration::SET_DEFAULT_UNATTENDED:
|
| - result = ShellIntegration::SetAsDefaultProtocolClient(protocol_);
|
| + case SET_DEFAULT_UNATTENDED:
|
| + if (SetAsDefaultProtocolClient(protocol_))
|
| + result = AttemptResult::SUCCESS;
|
| break;
|
| - case ShellIntegration::SET_DEFAULT_INTERACTIVE:
|
| - if (interactive_permitted) {
|
| - result = ShellIntegration::SetAsDefaultProtocolClientInteractive(
|
| - protocol_);
|
| + case SET_DEFAULT_INTERACTIVE:
|
| + if (interactive_permitted &&
|
| + SetAsDefaultProtocolClientInteractive(protocol_)) {
|
| + result = AttemptResult::SUCCESS;
|
| }
|
| break;
|
| + case SET_DEFAULT_ASYNCHRONOUS:
|
| + NOTREACHED();
|
| + break;
|
| }
|
| -
|
| - return result;
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&DefaultProtocolClientWorker::OnSetAsDefaultAttemptComplete,
|
| + this, result));
|
| }
|
|
|