blob: 4aaf0a1c35b3ab1a9fa5252fc5b7d5e2ef92b7ea [file] [log] [blame]
[email protected]5a20b192012-03-01 06:01:571// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]4a0765a2009-05-08 23:12:255#include "chrome/browser/shell_integration.h"
6
[email protected]c5efb952011-11-01 01:28:367#include "base/bind.h"
[email protected]28375ae2010-02-05 04:45:508#include "base/command_line.h"
thestig18dfb7a52014-08-26 10:44:049#include "base/files/file_util.h"
asvitkineaa060312016-09-01 22:44:1310#include "base/metrics/histogram_macros.h"
[email protected]24a555b62013-06-10 22:01:1711#include "base/strings/string_util.h"
pmonette9c1457f2015-11-19 20:29:3112#include "base/strings/stringprintf.h"
[email protected]e309f312013-06-07 21:50:0813#include "base/strings/utf_string_conversions.h"
Ben Wellsf54b3ba2017-10-11 05:07:2814#include "base/task_scheduler/lazy_task_runner.h"
pmonetteb18379f2017-06-01 01:18:4415#include "base/task_scheduler/post_task.h"
Ben Wellsf54b3ba2017-10-11 05:07:2816#include "base/task_scheduler/single_thread_task_runner_thread_mode.h"
Robert Liao9a8680d2017-07-17 19:58:3217#include "base/task_scheduler/task_traits.h"
[email protected]124901f52013-03-27 14:42:1018#include "base/threading/thread_restrictions.h"
avi664c07b2015-12-26 02:18:3119#include "build/build_config.h"
[email protected]ba26a442013-02-20 15:32:5520#include "chrome/browser/policy/policy_path_parser.h"
[email protected]b96aa932009-08-12 21:34:4921#include "chrome/common/chrome_paths.h"
[email protected]28375ae2010-02-05 04:45:5022#include "chrome/common/chrome_switches.h"
brettwb1fc1b82016-02-02 00:19:0823#include "components/prefs/pref_service.h"
sdefresne9fb67692015-08-03 18:48:2224#include "components/version_info/version_info.h"
[email protected]c38831a12011-10-28 12:44:4925#include "content/public/browser/browser_thread.h"
initial.commit09911bf2008-07-26 23:55:2926
[email protected]931d1042013-04-05 17:50:4427#if defined(OS_CHROMEOS)
28#include "chromeos/chromeos_switches.h"
29#endif
30
pmonette32a5cfb42016-04-11 22:04:4431#if defined(OS_WIN)
32#include "base/win/windows_version.h"
33#include "chrome/browser/shell_integration_win.h"
pmonette0c40087a2016-04-21 00:05:1634#include "chrome/installer/util/shell_util.h"
pmonette32a5cfb42016-04-11 22:04:4435#endif
36
[email protected]2f5bc322013-12-04 08:58:1537#if !defined(OS_WIN)
sdefresne9fb67692015-08-03 18:48:2238#include "chrome/common/channel_info.h"
[email protected]af39f002014-08-22 10:18:1839#include "chrome/grit/chromium_strings.h"
[email protected]2f5bc322013-12-04 08:58:1540#include "ui/base/l10n/l10n_util.h"
41#endif
42
[email protected]631bb742011-11-02 11:29:3943using content::BrowserThread;
44
pmonette9fa59e882016-02-10 00:12:1945namespace shell_integration {
46
pmonette034a03d92015-10-02 21:04:2747namespace {
48
pmonette9fa59e882016-02-10 00:12:1949const struct AppModeInfo* gAppModeInfo = nullptr;
pmonette034a03d92015-10-02 21:04:2750
Ben Wellsf54b3ba2017-10-11 05:07:2851// TODO(crbug.com/773563): Remove |g_sequenced_task_runner| and use an instance
52// field / singleton instead.
53#if defined(OS_WIN)
54base::LazyCOMSTATaskRunner g_sequenced_task_runner =
55 LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
56 base::TaskTraits(base::MayBlock()),
57 base::SingleThreadTaskRunnerThreadMode::SHARED);
58#else
59base::LazySequencedTaskRunner g_sequenced_task_runner =
60 LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(base::TaskTraits(base::MayBlock()));
61#endif
62
pmonette034a03d92015-10-02 21:04:2763} // namespace
64
pmonette32a5cfb42016-04-11 22:04:4465bool CanSetAsDefaultBrowser() {
66 return GetDefaultWebClientSetPermission() != SET_DEFAULT_NOT_ALLOWED;
[email protected]a01481b2011-07-15 04:30:0267}
68
pmonette034a03d92015-10-02 21:04:2769#if !defined(OS_WIN)
pmonette9fa59e882016-02-10 00:12:1970bool IsElevationNeededForSettingDefaultProtocolClient() {
pmonette034a03d92015-10-02 21:04:2771 return false;
72}
73#endif // !defined(OS_WIN)
[email protected]9561bc912012-03-07 02:41:1674
pmonette9fa59e882016-02-10 00:12:1975void SetAppModeInfo(const struct AppModeInfo* info) {
[email protected]9561bc912012-03-07 02:41:1676 gAppModeInfo = info;
77}
78
pmonette9fa59e882016-02-10 00:12:1979const struct AppModeInfo* AppModeInfo() {
[email protected]9561bc912012-03-07 02:41:1680 return gAppModeInfo;
81}
82
pmonette9fa59e882016-02-10 00:12:1983bool IsRunningInAppMode() {
[email protected]9561bc912012-03-07 02:41:1684 return gAppModeInfo != NULL;
85}
86
pmonette9fa59e882016-02-10 00:12:1987base::CommandLine CommandLineArgsForLauncher(
[email protected]2f1c09d2011-01-14 14:58:1488 const GURL& url,
[email protected]5c93a0c12012-05-02 19:45:2489 const std::string& extension_app_id,
[email protected]650b2d52013-02-10 03:41:4590 const base::FilePath& profile_path) {
Francois Doray66bdfd82017-10-20 13:50:3791 base::AssertBlockingAllowed();
avi556c05022014-12-22 23:31:4392 base::CommandLine new_cmd_line(base::CommandLine::NO_PROGRAM);
[email protected]28375ae2010-02-05 04:45:5093
[email protected]fb06aea82014-02-26 15:48:4794 AppendProfileArgs(
95 extension_app_id.empty() ? base::FilePath() : profile_path,
96 &new_cmd_line);
[email protected]28375ae2010-02-05 04:45:5097
98 // If |extension_app_id| is present, we use the kAppId switch rather than
99 // the kApp switch (the launch url will be read from the extension app
100 // during launch.
[email protected]ec5b50d2010-10-09 16:35:18101 if (!extension_app_id.empty()) {
[email protected]b10392932011-03-08 21:28:14102 new_cmd_line.AppendSwitchASCII(switches::kAppId, extension_app_id);
[email protected]64048bd2010-03-08 23:28:58103 } else {
[email protected]28375ae2010-02-05 04:45:50104 // Use '--app=url' instead of just 'url' to launch the browser with minimal
105 // chrome.
106 // Note: Do not change this flag! Old Gears shortcuts will break if you do!
[email protected]b10392932011-03-08 21:28:14107 new_cmd_line.AppendSwitchASCII(switches::kApp, url.spec());
[email protected]28375ae2010-02-05 04:45:50108 }
[email protected]b10392932011-03-08 21:28:14109 return new_cmd_line;
[email protected]28375ae2010-02-05 04:45:50110}
111
pmonette9fa59e882016-02-10 00:12:19112void AppendProfileArgs(const base::FilePath& profile_path,
113 base::CommandLine* command_line) {
[email protected]fb06aea82014-02-26 15:48:47114 DCHECK(command_line);
avi556c05022014-12-22 23:31:43115 const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
[email protected]fb06aea82014-02-26 15:48:47116
117 // Use the same UserDataDir for new launches that we currently have set.
118 base::FilePath user_data_dir =
119 cmd_line.GetSwitchValuePath(switches::kUserDataDir);
120#if defined(OS_MACOSX) || defined(OS_WIN)
121 policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
122#endif
123 if (!user_data_dir.empty()) {
124 // Make sure user_data_dir is an absolute path.
125 user_data_dir = base::MakeAbsoluteFilePath(user_data_dir);
126 if (!user_data_dir.empty() && base::PathExists(user_data_dir))
127 command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
128 }
129
130#if defined(OS_CHROMEOS)
131 base::FilePath profile = cmd_line.GetSwitchValuePath(
132 chromeos::switches::kLoginProfile);
133 if (!profile.empty())
134 command_line->AppendSwitchPath(chromeos::switches::kLoginProfile, profile);
135#else
136 if (!profile_path.empty())
137 command_line->AppendSwitchPath(switches::kProfileDirectory,
138 profile_path.BaseName());
139#endif
140}
141
[email protected]bd046bd42012-06-08 05:07:32142#if !defined(OS_WIN)
pmonette9fa59e882016-02-10 00:12:19143base::string16 GetAppShortcutsSubdirName() {
sdefresne9fb67692015-08-03 18:48:22144 if (chrome::GetChannel() == version_info::Channel::CANARY)
[email protected]2f5bc322013-12-04 08:58:15145 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY);
146 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME);
147}
pmonette868ca642015-09-02 14:34:02148#endif // !defined(OS_WIN)
[email protected]bd046bd42012-06-08 05:07:32149
pmonette034a03d92015-10-02 21:04:27150///////////////////////////////////////////////////////////////////////////////
pmonette9fa59e882016-02-10 00:12:19151// DefaultWebClientWorker
[email protected]d24c4012009-07-28 01:57:31152//
initial.commit09911bf2008-07-26 23:55:29153
pmonette9fa59e882016-02-10 00:12:19154void DefaultWebClientWorker::StartCheckIsDefault() {
Ben Wellsf54b3ba2017-10-11 05:07:28155 g_sequenced_task_runner.Get()->PostTask(
pmonetteb18379f2017-06-01 01:18:44156 FROM_HERE,
pmonette60a702c2016-03-22 22:59:40157 base::Bind(&DefaultWebClientWorker::CheckIsDefault, this, false));
[email protected]4468a5b2011-05-26 07:48:02158}
159
pmonette9fa59e882016-02-10 00:12:19160void DefaultWebClientWorker::StartSetAsDefault() {
Ben Wellsf54b3ba2017-10-11 05:07:28161 g_sequenced_task_runner.Get()->PostTask(
pmonetteb18379f2017-06-01 01:18:44162 FROM_HERE, base::Bind(&DefaultWebClientWorker::SetAsDefault, this));
initial.commit09911bf2008-07-26 23:55:29163}
164
[email protected]d24c4012009-07-28 01:57:31165///////////////////////////////////////////////////////////////////////////////
pmonette5207d8952016-03-22 15:53:08166// DefaultWebClientWorker, protected:
[email protected]d24c4012009-07-28 01:57:31167
pmonette5207d8952016-03-22 15:53:08168DefaultWebClientWorker::DefaultWebClientWorker(
169 const DefaultWebClientWorkerCallback& callback,
170 const char* worker_name)
171 : callback_(callback), worker_name_(worker_name) {}
172
173DefaultWebClientWorker::~DefaultWebClientWorker() = default;
[email protected]d24c4012009-07-28 01:57:31174
pmonette9fa59e882016-02-10 00:12:19175void DefaultWebClientWorker::OnCheckIsDefaultComplete(
pmonette60a702c2016-03-22 22:59:40176 DefaultWebClientState state,
177 bool is_following_set_as_default) {
thestig00844cea2015-09-08 21:44:52178 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]264f74d12009-09-04 23:39:58179 UpdateUI(state);
pmonette9c1457f2015-11-19 20:29:31180
pmonette60a702c2016-03-22 22:59:40181 if (is_following_set_as_default)
182 ReportSetDefaultResult(state);
pmonette5207d8952016-03-22 15:53:08183}
pmonettef89ac7c72015-10-06 03:22:01184
pmonette5207d8952016-03-22 15:53:08185///////////////////////////////////////////////////////////////////////////////
186// DefaultWebClientWorker, private:
pmonettef89ac7c72015-10-06 03:22:01187
pmonette60a702c2016-03-22 22:59:40188void DefaultWebClientWorker::CheckIsDefault(bool is_following_set_as_default) {
Francois Doray66bdfd82017-10-20 13:50:37189 base::AssertBlockingAllowed();
pmonetteb18379f2017-06-01 01:18:44190
pmonette5207d8952016-03-22 15:53:08191 DefaultWebClientState state = CheckIsDefaultImpl();
192 BrowserThread::PostTask(
193 BrowserThread::UI, FROM_HERE,
pmonette60a702c2016-03-22 22:59:40194 base::Bind(&DefaultBrowserWorker::OnCheckIsDefaultComplete, this, state,
195 is_following_set_as_default));
pmonette5207d8952016-03-22 15:53:08196}
197
198void DefaultWebClientWorker::SetAsDefault() {
Francois Doray66bdfd82017-10-20 13:50:37199 base::AssertBlockingAllowed();
pmonette32a5cfb42016-04-11 22:04:44200
201 // SetAsDefaultImpl will make sure the callback is executed exactly once.
202 SetAsDefaultImpl(
203 base::Bind(&DefaultWebClientWorker::CheckIsDefault, this, true));
[email protected]d24c4012009-07-28 01:57:31204}
205
pmonette60a702c2016-03-22 22:59:40206void DefaultWebClientWorker::ReportSetDefaultResult(
207 DefaultWebClientState state) {
pmonette9c1457f2015-11-19 20:29:31208 base::LinearHistogram::FactoryGet(
pmonette60a702c2016-03-22 22:59:40209 base::StringPrintf("%s.SetDefaultResult2", worker_name_), 1,
210 DefaultWebClientState::NUM_DEFAULT_STATES,
211 DefaultWebClientState::NUM_DEFAULT_STATES + 1,
pmonette9c1457f2015-11-19 20:29:31212 base::HistogramBase::kUmaTargetedHistogramFlag)
pmonette60a702c2016-03-22 22:59:40213 ->Add(state);
pmonettef89ac7c72015-10-06 03:22:01214}
215
pmonette9fa59e882016-02-10 00:12:19216void DefaultWebClientWorker::UpdateUI(DefaultWebClientState state) {
pmonettef9461d1a2016-03-08 18:13:47217 if (!callback_.is_null()) {
218 switch (state) {
219 case NOT_DEFAULT:
pmonettef9461d1a2016-03-08 18:13:47220 case IS_DEFAULT:
pmonettef9461d1a2016-03-08 18:13:47221 case UNKNOWN_DEFAULT:
Greg Thompson75b1c8e2017-08-16 13:36:28222 case OTHER_MODE_IS_DEFAULT:
223 callback_.Run(state);
224 return;
pmonettef9461d1a2016-03-08 18:13:47225 case NUM_DEFAULT_STATES:
pmonettef9461d1a2016-03-08 18:13:47226 break;
227 }
Greg Thompson75b1c8e2017-08-16 13:36:28228 NOTREACHED();
[email protected]d24c4012009-07-28 01:57:31229 }
initial.commit09911bf2008-07-26 23:55:29230}
[email protected]4468a5b2011-05-26 07:48:02231
232///////////////////////////////////////////////////////////////////////////////
pmonette9fa59e882016-02-10 00:12:19233// DefaultBrowserWorker
[email protected]4468a5b2011-05-26 07:48:02234//
235
pmonette586ab5b32016-03-07 19:50:37236DefaultBrowserWorker::DefaultBrowserWorker(
237 const DefaultWebClientWorkerCallback& callback)
pmonette5207d8952016-03-22 15:53:08238 : DefaultWebClientWorker(callback, "DefaultBrowser") {}
pmonettef89ac7c72015-10-06 03:22:01239
[email protected]4468a5b2011-05-26 07:48:02240///////////////////////////////////////////////////////////////////////////////
241// DefaultBrowserWorker, private:
242
pmonette5207d8952016-03-22 15:53:08243DefaultBrowserWorker::~DefaultBrowserWorker() = default;
244
245DefaultWebClientState DefaultBrowserWorker::CheckIsDefaultImpl() {
246 return GetDefaultBrowser();
[email protected]4468a5b2011-05-26 07:48:02247}
248
pmonette32a5cfb42016-04-11 22:04:44249void DefaultBrowserWorker::SetAsDefaultImpl(
250 const base::Closure& on_finished_callback) {
251 switch (GetDefaultWebClientSetPermission()) {
pmonettef89ac7c72015-10-06 03:22:01252 case SET_DEFAULT_NOT_ALLOWED:
[email protected]bd046bd42012-06-08 05:07:32253 NOTREACHED();
pmonettef89ac7c72015-10-06 03:22:01254 break;
255 case SET_DEFAULT_UNATTENDED:
pmonette60a702c2016-03-22 22:59:40256 SetAsDefaultBrowser();
pmonettef89ac7c72015-10-06 03:22:01257 break;
258 case SET_DEFAULT_INTERACTIVE:
pmonette32a5cfb42016-04-11 22:04:44259#if defined(OS_WIN)
260 if (interactive_permitted_) {
pmonette0c40087a2016-04-21 00:05:16261 switch (ShellUtil::GetInteractiveSetDefaultMode()) {
262 case ShellUtil::INTENT_PICKER:
263 win::SetAsDefaultBrowserUsingIntentPicker();
264 break;
265 case ShellUtil::SYSTEM_SETTINGS:
266 win::SetAsDefaultBrowserUsingSystemSettings(on_finished_callback);
267 // Early return because the function above takes care of calling
268 // |on_finished_callback|.
269 return;
pmonette32a5cfb42016-04-11 22:04:44270 }
271 }
272#endif // defined(OS_WIN)
pmonettef89ac7c72015-10-06 03:22:01273 break;
[email protected]bd046bd42012-06-08 05:07:32274 }
pmonette32a5cfb42016-04-11 22:04:44275 on_finished_callback.Run();
pmonette9c1457f2015-11-19 20:29:31276}
277
[email protected]4468a5b2011-05-26 07:48:02278///////////////////////////////////////////////////////////////////////////////
pmonette9fa59e882016-02-10 00:12:19279// DefaultProtocolClientWorker
[email protected]4468a5b2011-05-26 07:48:02280//
281
pmonette9fa59e882016-02-10 00:12:19282DefaultProtocolClientWorker::DefaultProtocolClientWorker(
pmonette586ab5b32016-03-07 19:50:37283 const DefaultWebClientWorkerCallback& callback,
284 const std::string& protocol)
pmonette5207d8952016-03-22 15:53:08285 : DefaultWebClientWorker(callback, "DefaultProtocolClient"),
286 protocol_(protocol) {}
287
288///////////////////////////////////////////////////////////////////////////////
289// DefaultProtocolClientWorker, protected:
290
291DefaultProtocolClientWorker::~DefaultProtocolClientWorker() = default;
[email protected]4468a5b2011-05-26 07:48:02292
293///////////////////////////////////////////////////////////////////////////////
294// DefaultProtocolClientWorker, private:
295
pmonette5207d8952016-03-22 15:53:08296DefaultWebClientState DefaultProtocolClientWorker::CheckIsDefaultImpl() {
297 return IsDefaultProtocolClient(protocol_);
[email protected]4468a5b2011-05-26 07:48:02298}
299
pmonette32a5cfb42016-04-11 22:04:44300void DefaultProtocolClientWorker::SetAsDefaultImpl(
301 const base::Closure& on_finished_callback) {
302 switch (GetDefaultWebClientSetPermission()) {
pmonettef89ac7c72015-10-06 03:22:01303 case SET_DEFAULT_NOT_ALLOWED:
304 // Not allowed, do nothing.
[email protected]e7f79872013-09-13 01:39:31305 break;
pmonettef89ac7c72015-10-06 03:22:01306 case SET_DEFAULT_UNATTENDED:
pmonette60a702c2016-03-22 22:59:40307 SetAsDefaultProtocolClient(protocol_);
[email protected]ee9d89d2012-09-25 18:21:03308 break;
pmonettef89ac7c72015-10-06 03:22:01309 case SET_DEFAULT_INTERACTIVE:
pmonette32a5cfb42016-04-11 22:04:44310#if defined(OS_WIN)
pmonette0c40087a2016-04-21 00:05:16311 if (interactive_permitted_) {
312 switch (ShellUtil::GetInteractiveSetDefaultMode()) {
313 case ShellUtil::INTENT_PICKER:
314 win::SetAsDefaultProtocolClientUsingIntentPicker(protocol_);
315 break;
316 case ShellUtil::SYSTEM_SETTINGS:
317 win::SetAsDefaultProtocolClientUsingSystemSettings(
318 protocol_, on_finished_callback);
319 // Early return because the function above takes care of calling
320 // |on_finished_callback|.
321 return;
322 }
323 }
pmonette32a5cfb42016-04-11 22:04:44324#endif // defined(OS_WIN)
[email protected]ee9d89d2012-09-25 18:21:03325 break;
[email protected]ee9d89d2012-09-25 18:21:03326 }
pmonette32a5cfb42016-04-11 22:04:44327 on_finished_callback.Run();
pmonette9c1457f2015-11-19 20:29:31328}
pmonette9fa59e882016-02-10 00:12:19329
330} // namespace shell_integration