OLD | NEW |
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 <windows.h> | 7 #include <windows.h> |
8 #include <shlwapi.h> | 8 #include <shlwapi.h> |
9 #include <shobjidl.h> | 9 #include <shobjidl.h> |
10 #include <propkey.h> // Needs to come after shobjidl.h. | 10 #include <propkey.h> // Needs to come after shobjidl.h. |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/files/file_enumerator.h" | 14 #include "base/files/file_enumerator.h" |
15 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
| 17 #include "base/metrics/field_trial.h" |
| 18 #include "base/metrics/histogram_macros.h" |
17 #include "base/path_service.h" | 19 #include "base/path_service.h" |
| 20 #include "base/process/launch.h" |
18 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
19 #include "base/strings/string_util.h" | 22 #include "base/strings/string_util.h" |
20 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
21 #include "base/strings/utf_string_conversions.h" | 24 #include "base/strings/utf_string_conversions.h" |
22 #include "base/win/registry.h" | 25 #include "base/win/registry.h" |
23 #include "base/win/scoped_comptr.h" | 26 #include "base/win/scoped_comptr.h" |
24 #include "base/win/scoped_propvariant.h" | 27 #include "base/win/scoped_propvariant.h" |
25 #include "base/win/shortcut.h" | 28 #include "base/win/shortcut.h" |
26 #include "base/win/windows_version.h" | 29 #include "base/win/windows_version.h" |
27 #include "chrome/browser/policy/policy_path_parser.h" | 30 #include "chrome/browser/policy/policy_path_parser.h" |
| 31 #include "chrome/browser/ui/startup/startup_browser_creator.h" |
28 #include "chrome/browser/web_applications/web_app.h" | 32 #include "chrome/browser/web_applications/web_app.h" |
29 #include "chrome/common/chrome_constants.h" | 33 #include "chrome/common/chrome_constants.h" |
30 #include "chrome/common/chrome_paths_internal.h" | 34 #include "chrome/common/chrome_paths_internal.h" |
31 #include "chrome/common/chrome_switches.h" | 35 #include "chrome/common/chrome_switches.h" |
32 #include "chrome/installer/setup/setup_util.h" | 36 #include "chrome/installer/setup/setup_util.h" |
33 #include "chrome/installer/util/browser_distribution.h" | 37 #include "chrome/installer/util/browser_distribution.h" |
34 #include "chrome/installer/util/create_reg_key_work_item.h" | 38 #include "chrome/installer/util/create_reg_key_work_item.h" |
35 #include "chrome/installer/util/install_util.h" | 39 #include "chrome/installer/util/install_util.h" |
36 #include "chrome/installer/util/set_reg_value_work_item.h" | 40 #include "chrome/installer/util/set_reg_value_work_item.h" |
37 #include "chrome/installer/util/shell_util.h" | 41 #include "chrome/installer/util/shell_util.h" |
38 #include "chrome/installer/util/util_constants.h" | 42 #include "chrome/installer/util/util_constants.h" |
39 #include "chrome/installer/util/work_item.h" | 43 #include "chrome/installer/util/work_item.h" |
40 #include "chrome/installer/util/work_item_list.h" | 44 #include "chrome/installer/util/work_item_list.h" |
| 45 #include "components/variations/variations_associated_data.h" |
41 #include "content/public/browser/browser_thread.h" | 46 #include "content/public/browser/browser_thread.h" |
42 | 47 |
43 using content::BrowserThread; | 48 using content::BrowserThread; |
44 | 49 |
45 namespace { | 50 namespace { |
46 | 51 |
47 const wchar_t kAppListAppNameSuffix[] = L"AppList"; | 52 const wchar_t kAppListAppNameSuffix[] = L"AppList"; |
48 | 53 |
| 54 const wchar_t kOpenWithCmdLineFormat[] = L"openwith.exe %ls"; |
| 55 const wchar_t kSetDefaultBrowserHelpUrl[] = |
| 56 L"https://support.google.com/chrome?p=default_browser"; |
| 57 |
| 58 const char kAsyncSetAsDefaultExperimentName[] = "AsyncSetAsDefault"; |
| 59 const char kEnableAsyncSetAsDefault[] = "enable-async-set-as-default"; |
| 60 const char kDisableAsyncSetAsDefault[] = "disable-async-set-as-default"; |
| 61 |
49 // Helper function for ShellIntegration::GetAppId to generates profile id | 62 // Helper function for ShellIntegration::GetAppId to generates profile id |
50 // from profile path. "profile_id" is composed of sanitized basenames of | 63 // from profile path. "profile_id" is composed of sanitized basenames of |
51 // user data dir and profile dir joined by a ".". | 64 // user data dir and profile dir joined by a ".". |
52 base::string16 GetProfileIdFromPath(const base::FilePath& profile_path) { | 65 base::string16 GetProfileIdFromPath(const base::FilePath& profile_path) { |
53 // Return empty string if profile_path is empty | 66 // Return empty string if profile_path is empty |
54 if (profile_path.empty()) | 67 if (profile_path.empty()) |
55 return base::string16(); | 68 return base::string16(); |
56 | 69 |
57 base::FilePath default_user_data_dir; | 70 base::FilePath default_user_data_dir; |
58 // Return empty string if profile_path is in default user data | 71 // Return empty string if profile_path is in default user data |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 case ShellUtil::NOT_DEFAULT: | 246 case ShellUtil::NOT_DEFAULT: |
234 return ShellIntegration::NOT_DEFAULT; | 247 return ShellIntegration::NOT_DEFAULT; |
235 case ShellUtil::IS_DEFAULT: | 248 case ShellUtil::IS_DEFAULT: |
236 return ShellIntegration::IS_DEFAULT; | 249 return ShellIntegration::IS_DEFAULT; |
237 default: | 250 default: |
238 DCHECK_EQ(ShellUtil::UNKNOWN_DEFAULT, default_state); | 251 DCHECK_EQ(ShellUtil::UNKNOWN_DEFAULT, default_state); |
239 return ShellIntegration::UNKNOWN_DEFAULT; | 252 return ShellIntegration::UNKNOWN_DEFAULT; |
240 } | 253 } |
241 } | 254 } |
242 | 255 |
| 256 // Resets the default browser choice for the current user. |
| 257 void ResetDefaultBrowser() { |
| 258 static const wchar_t* kUrlAssociationKeyFormats[] = { |
| 259 L"SOFTWARE\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\" |
| 260 L"%ls\\UserChoice", |
| 261 L"SOFTWARE\\Microsoft\\Windows\\Roaming\\OpenWith\\UrlAssociations\\" |
| 262 L"%ls\\UserChoice"}; |
| 263 static const wchar_t* kProtocols[] = {L"http", L"https"}; |
| 264 |
| 265 for (const wchar_t* format : kUrlAssociationKeyFormats) { |
| 266 for (const wchar_t* protocol : kProtocols) { |
| 267 base::win::RegKey registry_key( |
| 268 HKEY_CURRENT_USER, base::StringPrintf(format, protocol).c_str(), |
| 269 KEY_WRITE); |
| 270 registry_key.DeleteValue(L"Hash"); |
| 271 } |
| 272 } |
| 273 } |
| 274 |
| 275 // Returns true if the AsyncSetAsDefault field trial is activated. |
| 276 bool IsAsyncSetAsDefaultEnabled() { |
| 277 using base::CommandLine; |
| 278 |
| 279 const std::string group_name = |
| 280 base::FieldTrialList::FindFullName("AsyncSetAsDefault"); |
| 281 if (CommandLine::ForCurrentProcess()->HasSwitch(kDisableAsyncSetAsDefault)) |
| 282 return false; |
| 283 if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableAsyncSetAsDefault)) |
| 284 return true; |
| 285 |
| 286 return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE); |
| 287 } |
| 288 |
243 } // namespace | 289 } // namespace |
244 | 290 |
| 291 // static |
| 292 bool ShellIntegration::IsSetAsDefaultAsynchronous() { |
| 293 return base::win::GetVersion() >= base::win::VERSION_WIN10 && |
| 294 IsAsyncSetAsDefaultEnabled(); |
| 295 } |
| 296 |
| 297 void ShellIntegration::SetAsDefaultBrowserAsynchronous() { |
| 298 DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN10); |
| 299 |
| 300 ResetDefaultBrowser(); |
| 301 base::LaunchProcess( |
| 302 base::StringPrintf(kOpenWithCmdLineFormat, kSetDefaultBrowserHelpUrl), |
| 303 base::LaunchOptions()); |
| 304 } |
| 305 |
245 ShellIntegration::DefaultWebClientSetPermission | 306 ShellIntegration::DefaultWebClientSetPermission |
246 ShellIntegration::CanSetAsDefaultBrowser() { | 307 ShellIntegration::CanSetAsDefaultBrowser() { |
247 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 308 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
248 if (distribution->GetDefaultBrowserControlPolicy() != | 309 if (distribution->GetDefaultBrowserControlPolicy() != |
249 BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) | 310 BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) |
250 return SET_DEFAULT_NOT_ALLOWED; | 311 return SET_DEFAULT_NOT_ALLOWED; |
251 | 312 |
252 if (ShellUtil::CanMakeChromeDefaultUnattended()) | 313 if (ShellUtil::CanMakeChromeDefaultUnattended()) |
253 return SET_DEFAULT_UNATTENDED; | 314 return SET_DEFAULT_UNATTENDED; |
| 315 else if (IsSetAsDefaultAsynchronous()) |
| 316 return SET_DEFAULT_ASYNCHRONOUS; |
254 else | 317 else |
255 return SET_DEFAULT_INTERACTIVE; | 318 return SET_DEFAULT_INTERACTIVE; |
256 } | 319 } |
257 | 320 |
258 bool ShellIntegration::SetAsDefaultBrowser() { | 321 bool ShellIntegration::SetAsDefaultBrowser() { |
259 base::FilePath chrome_exe; | 322 base::FilePath chrome_exe; |
260 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 323 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
261 LOG(ERROR) << "Error getting app exe path"; | 324 LOG(ERROR) << "Error getting app exe path"; |
262 return false; | 325 return false; |
263 } | 326 } |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
581 } | 644 } |
582 | 645 |
583 shortcut = shortcut.Append(shortcut_name).Append(shortcut_name + | 646 shortcut = shortcut.Append(shortcut_name).Append(shortcut_name + |
584 installer::kLnkExt); | 647 installer::kLnkExt); |
585 if (base::PathExists(shortcut)) | 648 if (base::PathExists(shortcut)) |
586 return shortcut; | 649 return shortcut; |
587 } | 650 } |
588 | 651 |
589 return base::FilePath(); | 652 return base::FilePath(); |
590 } | 653 } |
| 654 |
| 655 void ShellIntegration::DefaultBrowserWorker::InitializeSetAsDefault() { |
| 656 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 657 |
| 658 if (IsSetAsDefaultAsynchronous()) { |
| 659 StartupBrowserCreator::AddUrlFilter( |
| 660 GURL(kSetDefaultBrowserHelpUrl), |
| 661 base::Bind(&DefaultBrowserWorker::CompleteSetAsDefault, this, true)); |
| 662 |
| 663 // Remember the start time. |
| 664 start_time_ = base::TimeTicks::Now(); |
| 665 |
| 666 // Start the timer. |
| 667 if (!async_timer_) |
| 668 async_timer_.reset(new base::OneShotTimer<DefaultWebClientWorker>()); |
| 669 |
| 670 base::TimeDelta timer_duration = base::TimeDelta::FromMinutes(2); |
| 671 std::string value = variations::GetVariationParamValue( |
| 672 kAsyncSetAsDefaultExperimentName, "TimerDuration"); |
| 673 if (!value.empty()) |
| 674 timer_duration = base::TimeDelta::FromSeconds(std::atoi(value.c_str())); |
| 675 |
| 676 async_timer_->Start( |
| 677 FROM_HERE, timer_duration, |
| 678 base::Bind(&DefaultBrowserWorker::CompleteSetAsDefault, this, false)); |
| 679 } |
| 680 } |
| 681 |
| 682 bool ShellIntegration::DefaultBrowserWorker::UninitializeSetAsDefault( |
| 683 bool succeeded) { |
| 684 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 685 |
| 686 if (IsSetAsDefaultAsynchronous()) { |
| 687 GURL default_browser_help_url(kSetDefaultBrowserHelpUrl); |
| 688 if (!async_timer_) { |
| 689 // If the timer isnt set, that means it has already fired and |
| 690 // the observer should not be notified again. |
| 691 DCHECK(!StartupBrowserCreator::UrlFilterExists(default_browser_help_url)); |
| 692 return false; |
| 693 } |
| 694 |
| 695 // Record the duration from starting to set as default browser to now. |
| 696 UMA_HISTOGRAM_BOOLEAN("AsyncSetAsDefault.Succeeded", succeeded); |
| 697 UMA_HISTOGRAM_TIMES("AsyncSetAsDefault.Duration", |
| 698 base::TimeTicks::Now() - start_time_); |
| 699 |
| 700 // Destroy timer. |
| 701 async_timer_.reset(); |
| 702 |
| 703 // Remove filter if it exists. |
| 704 if (StartupBrowserCreator::UrlFilterExists(default_browser_help_url)) |
| 705 StartupBrowserCreator::RemoveUrlFilter(default_browser_help_url); |
| 706 } |
| 707 return true; |
| 708 } |
OLD | NEW |