Index: chrome/browser/shell_integration.cc |
diff --git a/chrome/browser/shell_integration.cc b/chrome/browser/shell_integration.cc |
index 25e8ec7c55a6a087273821b26f6a3be7c7bb0be8..66e1db97078c8fda435d40f13b068be5ad4f53bc 100644 |
--- a/chrome/browser/shell_integration.cc |
+++ b/chrome/browser/shell_integration.cc |
@@ -7,10 +7,13 @@ |
#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/stringprintf.h" |
grt (UTC plus 2)
2015/10/02 23:13:56
unused?
Patrick Monette
2015/10/05 15:54:31
Done.
|
#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 +45,11 @@ bool ShellIntegration::SetAsDefaultBrowserInteractive() { |
} |
// static |
+bool ShellIntegration::IsSetAsDefaultAsynchronous() { |
+ return false; |
+} |
+ |
+// static |
bool ShellIntegration::SetAsDefaultProtocolClientInteractive( |
const std::string& protocol) { |
return false; |
@@ -53,7 +61,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 +174,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 +242,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 +354,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 +422,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)); |
} |