Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Side by Side Diff: chrome/browser/shell_integration.cc

Issue 1349163008: Setting chrome as the default browser is now fixed on Windows 10 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added detailed metrics Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/shell_integration.h" 5 #include "chrome/browser/shell_integration.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
10 #include "base/metrics/histogram_macros.h"
10 #include "base/prefs/pref_service.h" 11 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
13 #include "base/threading/thread_restrictions.h" 14 #include "base/threading/thread_restrictions.h"
15 #include "base/timer/timer.h"
14 #include "chrome/browser/policy/policy_path_parser.h" 16 #include "chrome/browser/policy/policy_path_parser.h"
15 #include "chrome/common/chrome_paths.h" 17 #include "chrome/common/chrome_paths.h"
16 #include "chrome/common/chrome_switches.h" 18 #include "chrome/common/chrome_switches.h"
17 #include "components/version_info/version_info.h" 19 #include "components/version_info/version_info.h"
18 #include "content/public/browser/browser_thread.h" 20 #include "content/public/browser/browser_thread.h"
19 21
20 #if defined(OS_CHROMEOS) 22 #if defined(OS_CHROMEOS)
21 #include "chromeos/chromeos_switches.h" 23 #include "chromeos/chromeos_switches.h"
22 #endif 24 #endif
23 25
24 #if !defined(OS_WIN) 26 #if !defined(OS_WIN)
25 #include "chrome/common/channel_info.h" 27 #include "chrome/common/channel_info.h"
26 #include "chrome/grit/chromium_strings.h" 28 #include "chrome/grit/chromium_strings.h"
27 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
28 #endif 30 #endif
29 31
30 using content::BrowserThread; 32 using content::BrowserThread;
31 33
32 // static 34 // static
33 ShellIntegration::DefaultWebClientSetPermission 35 ShellIntegration::DefaultWebClientSetPermission
34 ShellIntegration::CanSetAsDefaultProtocolClient() { 36 ShellIntegration::CanSetAsDefaultProtocolClient() {
35 // Allowed as long as the browser can become the operating system default 37 // Allowed as long as the browser can become the operating system default
36 // browser. 38 // browser.
37 return CanSetAsDefaultBrowser(); 39 DefaultWebClientSetPermission permission = CanSetAsDefaultBrowser();
40
41 // Set as default asynchronous is only supported for default web browser.
42 return (permission == SET_DEFAULT_ASYNCHRONOUS) ? SET_DEFAULT_INTERACTIVE
43 : permission;
38 } 44 }
39 45
40 static const struct ShellIntegration::AppModeInfo* gAppModeInfo = NULL; 46 static const struct ShellIntegration::AppModeInfo* gAppModeInfo = NULL;
41 47
42 // static 48 // static
43 void ShellIntegration::SetAppModeInfo(const struct AppModeInfo* info) { 49 void ShellIntegration::SetAppModeInfo(const struct AppModeInfo* info) {
44 gAppModeInfo = info; 50 gAppModeInfo = info;
45 } 51 }
46 52
47 // static 53 // static
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 if (chrome::GetChannel() == version_info::Channel::CANARY) 123 if (chrome::GetChannel() == version_info::Channel::CANARY)
118 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY); 124 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY);
119 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME); 125 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME);
120 } 126 }
121 127
122 // static 128 // static
123 bool ShellIntegration::SetAsDefaultBrowserInteractive() { 129 bool ShellIntegration::SetAsDefaultBrowserInteractive() {
124 return false; 130 return false;
125 } 131 }
126 132
133 #if !defined(OS_WIN)
134 // static
135 bool ShellIntegration::IsSetAsDefaultAsynchronous() {
136 return false;
137 }
138 #endif // !defined(OS_WIN)
139
127 // static 140 // static
128 bool ShellIntegration::SetAsDefaultProtocolClientInteractive( 141 bool ShellIntegration::SetAsDefaultProtocolClientInteractive(
129 const std::string& protocol) { 142 const std::string& protocol) {
130 return false; 143 return false;
131 } 144 }
132 145
133 // static 146 // static
134 bool ShellIntegration::IsElevationNeededForSettingDefaultProtocolClient() { 147 bool ShellIntegration::IsElevationNeededForSettingDefaultProtocolClient() {
135 return false; 148 return false;
136 } 149 }
137 150
138 #endif // !defined(OS_WIN) 151 #endif // !defined(OS_WIN)
139 152
140 bool ShellIntegration::DefaultWebClientObserver::IsOwnedByWorker() { 153 bool ShellIntegration::DefaultWebClientObserver::IsOwnedByWorker() {
141 return false; 154 return false;
142 } 155 }
143 156
144 bool ShellIntegration::DefaultWebClientObserver:: 157 bool ShellIntegration::DefaultWebClientObserver::
145 IsInteractiveSetDefaultPermitted() { 158 IsInteractiveSetDefaultPermitted() {
146 return false; 159 return false;
147 } 160 }
148 161
149 /////////////////////////////////////////////////////////////////////////////// 162 ///////////////////////////////////////////////////////////////////////////////
150 // ShellIntegration::DefaultWebClientWorker 163 // ShellIntegration::DefaultWebClientWorker
151 // 164 //
152 165
153 ShellIntegration::DefaultWebClientWorker::DefaultWebClientWorker( 166 ShellIntegration::DefaultWebClientWorker::DefaultWebClientWorker(
154 DefaultWebClientObserver* observer) 167 DefaultWebClientObserver* observer)
155 : observer_(observer) { 168 : observer_(observer) {}
156 }
157 169
158 void ShellIntegration::DefaultWebClientWorker::StartCheckIsDefault() { 170 void ShellIntegration::DefaultWebClientWorker::StartCheckIsDefault() {
159 if (observer_) { 171 if (observer_) {
160 observer_->SetDefaultWebClientUIState(STATE_PROCESSING); 172 observer_->SetDefaultWebClientUIState(STATE_PROCESSING);
161 BrowserThread::PostTask( 173 BrowserThread::PostTask(
162 BrowserThread::FILE, FROM_HERE, 174 BrowserThread::FILE, FROM_HERE,
163 base::Bind( 175 base::Bind(&DefaultWebClientWorker::CheckIsDefault, this));
164 &DefaultWebClientWorker::ExecuteCheckIsDefault, this));
165 } 176 }
166 } 177 }
167 178
168 void ShellIntegration::DefaultWebClientWorker::StartSetAsDefault() { 179 void ShellIntegration::DefaultWebClientWorker::StartSetAsDefault() {
180 // Cancel the already running process if another start is requested.
181 if (set_as_default_in_progress_) {
182 if (set_as_default_initialized_)
183 FinalizeSetAsDefault();
grt (UTC plus 2) 2015/10/02 17:39:18 set_as_default_initialized_ = false; so that the v
Patrick Monette 2015/10/02 20:15:13 Done.
184
185 if (ShouldReportAttemptResults())
186 ReportAttemptResult(AttemptResult::RETRY);
187 }
188
189 set_as_default_in_progress_ = true;
169 bool interactive_permitted = false; 190 bool interactive_permitted = false;
170 if (observer_) { 191 if (observer_) {
171 observer_->SetDefaultWebClientUIState(STATE_PROCESSING); 192 observer_->SetDefaultWebClientUIState(STATE_PROCESSING);
172 interactive_permitted = observer_->IsInteractiveSetDefaultPermitted(); 193 interactive_permitted = observer_->IsInteractiveSetDefaultPermitted();
194
195 // The initialization is only useful when there is an observer.
196 set_as_default_initialized_ = InitializeSetAsDefault();
173 } 197 }
174 BrowserThread::PostTask( 198
175 BrowserThread::FILE, FROM_HERE, 199 // Remember the start time.
176 base::Bind(&DefaultWebClientWorker::ExecuteSetAsDefault, this, 200 start_time_ = base::TimeTicks::Now();
177 interactive_permitted)); 201
202 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
203 base::Bind(&DefaultWebClientWorker::SetAsDefault,
204 this, interactive_permitted));
178 } 205 }
179 206
180 void ShellIntegration::DefaultWebClientWorker::ObserverDestroyed() { 207 void ShellIntegration::DefaultWebClientWorker::ObserverDestroyed() {
181 // Our associated view has gone away, so we shouldn't call back to it if 208 // Our associated view has gone away, so we shouldn't call back to it if
182 // our worker thread returns after the view is dead. 209 // our worker thread returns after the view is dead.
183 DCHECK_CURRENTLY_ON(BrowserThread::UI); 210 DCHECK_CURRENTLY_ON(BrowserThread::UI);
184 observer_ = NULL; 211 observer_ = nullptr;
212
213 if (set_as_default_initialized_) {
214 FinalizeSetAsDefault();
215 set_as_default_initialized_ = false;
216 }
185 } 217 }
186 218
187 /////////////////////////////////////////////////////////////////////////////// 219 ///////////////////////////////////////////////////////////////////////////////
188 // DefaultWebClientWorker, private: 220 // DefaultWebClientWorker, private:
189 221
190 void ShellIntegration::DefaultWebClientWorker::ExecuteCheckIsDefault() { 222 ShellIntegration::DefaultWebClientWorker::~DefaultWebClientWorker() {
191 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 223 if (set_as_default_in_progress_ && ShouldReportAttemptResults())
grt (UTC plus 2) 2015/10/02 17:39:18 since this represents the observer walking away fr
Patrick Monette 2015/10/02 20:15:13 Done.
192 DefaultWebClientState state = CheckIsDefault(); 224 ReportAttemptResult(AttemptResult::ABANDONED);
193 BrowserThread::PostTask(
194 BrowserThread::UI, FROM_HERE,
195 base::Bind(
196 &DefaultWebClientWorker::CompleteCheckIsDefault, this, state));
197 } 225 }
198 226
199 void ShellIntegration::DefaultWebClientWorker::CompleteCheckIsDefault( 227 void ShellIntegration::DefaultWebClientWorker::OnCheckIsDefaultComplete(
200 DefaultWebClientState state) { 228 DefaultWebClientState state) {
201 DCHECK_CURRENTLY_ON(BrowserThread::UI); 229 DCHECK_CURRENTLY_ON(BrowserThread::UI);
202 UpdateUI(state); 230 UpdateUI(state);
203 // The worker has finished everything it needs to do, so free the observer 231 // The worker has finished everything it needs to do, so free the observer
204 // if we own it. 232 // if we own it.
205 if (observer_ && observer_->IsOwnedByWorker()) { 233 if (observer_ && observer_->IsOwnedByWorker()) {
206 delete observer_; 234 delete observer_;
207 observer_ = NULL; 235 observer_ = nullptr;
208 } 236 }
209 } 237 }
210 238
211 void ShellIntegration::DefaultWebClientWorker::ExecuteSetAsDefault( 239 void ShellIntegration::DefaultWebClientWorker::OnSetAsDefaultAttemptComplete(
212 bool interactive_permitted) { 240 AttemptResult result) {
213 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 241 DCHECK_CURRENTLY_ON(BrowserThread::UI);
242 // Hold on to a reference because if this was called via the default browser
243 // callback in StartupBrowserCreator, clearing the callback in
244 // FinalizeSetAsDefault would otherwise remove the last reference and delete
245 // us in the middle of this function.
246 scoped_refptr<DefaultWebClientWorker> scoped_ref(this);
214 247
215 bool result = SetAsDefault(interactive_permitted); 248 if (set_as_default_in_progress_) {
216 BrowserThread::PostTask( 249 set_as_default_in_progress_ = false;
217 BrowserThread::UI, FROM_HERE, 250
218 base::Bind(&DefaultWebClientWorker::CompleteSetAsDefault, this, result)); 251 if (set_as_default_initialized_) {
252 FinalizeSetAsDefault();
253 set_as_default_initialized_ = false;
254 }
255 if (observer_) {
256 bool succeeded = result == AttemptResult::SUCCESS ||
257 result == AttemptResult::ALREADY_DEFAULT;
258 observer_->OnSetAsDefaultConcluded(succeeded);
259 }
260
261 if (ShouldReportAttemptResults())
262 ReportAttemptResult(result);
263
264 // Start the default browser check which will notify the observer as to
265 // whether Chrome is really the default browser. This is needed because
266 // detecting that the process was successful is not 100% sure.
267 // For example, on Windows 10+, the user might have unchecked the "Always
268 // use this app" checkbox which can't be detected.
269 StartCheckIsDefault();
270 }
219 } 271 }
220 272
221 void ShellIntegration::DefaultWebClientWorker::CompleteSetAsDefault( 273 void ShellIntegration::DefaultWebClientWorker::ReportAttemptResult(
222 bool succeeded) { 274 AttemptResult result) {
223 DCHECK_CURRENTLY_ON(BrowserThread::UI); 275 DCHECK(ShouldReportAttemptResults());
grt (UTC plus 2) 2015/10/02 17:39:18 how about: if (!ShouldReportAttemptResults())
Patrick Monette 2015/10/02 20:15:14 Done.
224 // First tell the observer what the SetAsDefault call has returned. 276
225 if (observer_) 277 UMA_HISTOGRAM_ENUMERATION("DefaultBrowser.AsyncSetAsDefault.Result", result,
226 observer_->OnSetAsDefaultConcluded(succeeded); 278 AttemptResult::NUM_ATTEMPT_RESULT_TYPES);
227 // Set as default completed, check again to make sure it stuck... 279 UMA_HISTOGRAM_MEDIUM_TIMES("DefaultBrowser.AsyncSetAsDefault.Duration",
228 StartCheckIsDefault(); 280 base::TimeTicks::Now() - start_time_);
grt (UTC plus 2) 2015/10/02 17:39:18 the times we care about are: - time to success (in
Patrick Monette 2015/10/02 20:15:13 Done.
229 } 281 }
230 282
283 bool ShellIntegration::DefaultWebClientWorker::InitializeSetAsDefault() {
284 return true;
285 }
286
287 void ShellIntegration::DefaultWebClientWorker::FinalizeSetAsDefault() {}
288
289 #if !defined(OS_WIN)
290 // static
291 bool ShellIntegration::DefaultWebClientWorker::ShouldReportAttemptResults() {
292 return false;
293 }
294 #endif // !defined(OS_WIN)
295
231 void ShellIntegration::DefaultWebClientWorker::UpdateUI( 296 void ShellIntegration::DefaultWebClientWorker::UpdateUI(
232 DefaultWebClientState state) { 297 DefaultWebClientState state) {
233 if (observer_) { 298 if (observer_) {
234 switch (state) { 299 switch (state) {
235 case NOT_DEFAULT: 300 case NOT_DEFAULT:
236 observer_->SetDefaultWebClientUIState(STATE_NOT_DEFAULT); 301 observer_->SetDefaultWebClientUIState(STATE_NOT_DEFAULT);
237 break; 302 break;
238 case IS_DEFAULT: 303 case IS_DEFAULT:
239 observer_->SetDefaultWebClientUIState(STATE_IS_DEFAULT); 304 observer_->SetDefaultWebClientUIState(STATE_IS_DEFAULT);
240 break; 305 break;
241 case UNKNOWN_DEFAULT: 306 case UNKNOWN_DEFAULT:
242 observer_->SetDefaultWebClientUIState(STATE_UNKNOWN); 307 observer_->SetDefaultWebClientUIState(STATE_UNKNOWN);
243 break; 308 break;
244 default: 309 default:
245 break; 310 break;
246 } 311 }
247 } 312 }
248 } 313 }
249 314
250 /////////////////////////////////////////////////////////////////////////////// 315 ///////////////////////////////////////////////////////////////////////////////
251 // ShellIntegration::DefaultBrowserWorker 316 // ShellIntegration::DefaultBrowserWorker
252 // 317 //
253 318
254 ShellIntegration::DefaultBrowserWorker::DefaultBrowserWorker( 319 ShellIntegration::DefaultBrowserWorker::DefaultBrowserWorker(
255 DefaultWebClientObserver* observer) 320 DefaultWebClientObserver* observer)
256 : DefaultWebClientWorker(observer) { 321 : DefaultWebClientWorker(observer) {
257 } 322 }
258 323
324 ShellIntegration::DefaultBrowserWorker::~DefaultBrowserWorker() {}
325
259 /////////////////////////////////////////////////////////////////////////////// 326 ///////////////////////////////////////////////////////////////////////////////
260 // DefaultBrowserWorker, private: 327 // DefaultBrowserWorker, private:
261 328
262 ShellIntegration::DefaultWebClientState 329 void ShellIntegration::DefaultBrowserWorker::CheckIsDefault() {
263 ShellIntegration::DefaultBrowserWorker::CheckIsDefault() { 330 DefaultWebClientState state = GetDefaultBrowser();
264 return ShellIntegration::GetDefaultBrowser(); 331 BrowserThread::PostTask(
332 BrowserThread::UI, FROM_HERE,
333 base::Bind(&DefaultBrowserWorker::OnCheckIsDefaultComplete, this, state));
265 } 334 }
266 335
267 bool ShellIntegration::DefaultBrowserWorker::SetAsDefault( 336 void ShellIntegration::DefaultBrowserWorker::SetAsDefault(
268 bool interactive_permitted) { 337 bool interactive_permitted) {
269 bool result = false; 338 AttemptResult result = AttemptResult::FAILURE;
270 switch (ShellIntegration::CanSetAsDefaultBrowser()) { 339 switch (CanSetAsDefaultBrowser()) {
271 case ShellIntegration::SET_DEFAULT_UNATTENDED: 340 case SET_DEFAULT_NOT_ALLOWED:
272 result = ShellIntegration::SetAsDefaultBrowser(); 341 NOTREACHED();
273 break; 342 break;
274 case ShellIntegration::SET_DEFAULT_INTERACTIVE: 343 case SET_DEFAULT_UNATTENDED:
275 if (interactive_permitted) 344 if (SetAsDefaultBrowser())
276 result = ShellIntegration::SetAsDefaultBrowserInteractive(); 345 result = AttemptResult::SUCCESS;
277 break; 346 break;
278 default: 347 case SET_DEFAULT_INTERACTIVE:
348 if (interactive_permitted && SetAsDefaultBrowserInteractive())
349 result = AttemptResult::SUCCESS;
350 break;
351 case SET_DEFAULT_ASYNCHRONOUS:
352 #if defined(OS_WIN)
353 if (!interactive_permitted)
354 break;
355 if (GetDefaultBrowser() == IS_DEFAULT) {
356 // Don't start the asynchronous operation since it could result in
357 // losing the default browser status.
358 result = AttemptResult::ALREADY_DEFAULT;
359 break;
360 }
361 // This function will cause OnSetAsDefaultAttemptComplete() to be called
362 // asynchronously via a filter established in InitializeSetAsDefault().
363 if (!SetAsDefaultBrowserAsynchronous()) {
364 result = AttemptResult::LAUNCH_FAILURE;
365 break;
366 }
367 return;
368 #else
279 NOTREACHED(); 369 NOTREACHED();
370 break;
371 #endif
280 } 372 }
281 373 BrowserThread::PostTask(
282 return result; 374 BrowserThread::UI, FROM_HERE,
375 base::Bind(&DefaultBrowserWorker::OnSetAsDefaultAttemptComplete, this,
376 result));
283 } 377 }
284 378
285 /////////////////////////////////////////////////////////////////////////////// 379 ///////////////////////////////////////////////////////////////////////////////
286 // ShellIntegration::DefaultProtocolClientWorker 380 // ShellIntegration::DefaultProtocolClientWorker
287 // 381 //
288 382
289 ShellIntegration::DefaultProtocolClientWorker::DefaultProtocolClientWorker( 383 ShellIntegration::DefaultProtocolClientWorker::DefaultProtocolClientWorker(
290 DefaultWebClientObserver* observer, const std::string& protocol) 384 DefaultWebClientObserver* observer, const std::string& protocol)
291 : DefaultWebClientWorker(observer), 385 : DefaultWebClientWorker(observer),
292 protocol_(protocol) { 386 protocol_(protocol) {
293 } 387 }
294 388
295 /////////////////////////////////////////////////////////////////////////////// 389 ///////////////////////////////////////////////////////////////////////////////
296 // DefaultProtocolClientWorker, private: 390 // DefaultProtocolClientWorker, private:
297 391
298 ShellIntegration::DefaultWebClientState 392 ShellIntegration::DefaultProtocolClientWorker::~DefaultProtocolClientWorker() {}
299 ShellIntegration::DefaultProtocolClientWorker::CheckIsDefault() { 393
300 return ShellIntegration::IsDefaultProtocolClient(protocol_); 394 void ShellIntegration::DefaultProtocolClientWorker::CheckIsDefault() {
395 DefaultWebClientState state = IsDefaultProtocolClient(protocol_);
396 BrowserThread::PostTask(
397 BrowserThread::UI, FROM_HERE,
398 base::Bind(&DefaultProtocolClientWorker::OnCheckIsDefaultComplete, this,
399 state));
301 } 400 }
302 401
303 bool ShellIntegration::DefaultProtocolClientWorker::SetAsDefault( 402 void ShellIntegration::DefaultProtocolClientWorker::SetAsDefault(
304 bool interactive_permitted) { 403 bool interactive_permitted) {
305 bool result = false; 404 AttemptResult result = AttemptResult::FAILURE;
306 switch (ShellIntegration::CanSetAsDefaultProtocolClient()) { 405 switch (CanSetAsDefaultProtocolClient()) {
307 case ShellIntegration::SET_DEFAULT_NOT_ALLOWED: 406 case SET_DEFAULT_NOT_ALLOWED:
308 result = false; 407 // Not allowed, do nothing.
309 break; 408 break;
310 case ShellIntegration::SET_DEFAULT_UNATTENDED: 409 case SET_DEFAULT_UNATTENDED:
311 result = ShellIntegration::SetAsDefaultProtocolClient(protocol_); 410 if (SetAsDefaultProtocolClient(protocol_))
411 result = AttemptResult::SUCCESS;
312 break; 412 break;
313 case ShellIntegration::SET_DEFAULT_INTERACTIVE: 413 case SET_DEFAULT_INTERACTIVE:
314 if (interactive_permitted) { 414 if (interactive_permitted &&
315 result = ShellIntegration::SetAsDefaultProtocolClientInteractive( 415 SetAsDefaultProtocolClientInteractive(protocol_)) {
316 protocol_); 416 result = AttemptResult::SUCCESS;
317 } 417 }
318 break; 418 break;
419 case SET_DEFAULT_ASYNCHRONOUS:
420 NOTREACHED();
421 break;
319 } 422 }
320 423 BrowserThread::PostTask(
321 return result; 424 BrowserThread::UI, FROM_HERE,
425 base::Bind(&DefaultProtocolClientWorker::OnSetAsDefaultAttemptComplete,
426 this, result));
322 } 427 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698