[M120 Migration]Fix for crash during chrome exit
[platform/framework/web/chromium-efl.git] / chrome / browser / shell_integration.cc
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/shell_integration.h"
6
7 #include <utility>
8
9 #include "base/command_line.h"
10 #include "base/files/file_util.h"
11 #include "base/functional/bind.h"
12 #include "base/i18n/file_util_icu.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/task/lazy_thread_pool_task_runner.h"
18 #include "base/task/single_thread_task_runner_thread_mode.h"
19 #include "base/task/task_traits.h"
20 #include "base/threading/scoped_blocking_call.h"
21 #include "build/branding_buildflags.h"
22 #include "build/build_config.h"
23 #include "build/chromeos_buildflags.h"
24 #include "chrome/browser/policy/policy_path_parser.h"
25 #include "chrome/common/chrome_paths.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "components/prefs/pref_service.h"
28 #include "components/version_info/version_info.h"
29 #include "content/public/browser/browser_task_traits.h"
30 #include "content/public/browser/browser_thread.h"
31
32 #if BUILDFLAG(IS_CHROMEOS_ASH)
33 #include "ash/constants/ash_switches.h"
34 #endif
35
36 #if BUILDFLAG(IS_WIN)
37 #include "base/win/windows_version.h"
38 #include "chrome/browser/shell_integration_win.h"
39 #include "chrome/installer/util/shell_util.h"
40 #endif
41
42 #if !BUILDFLAG(IS_WIN)
43 #include "chrome/common/channel_info.h"
44 #include "chrome/grit/branded_strings.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #endif
47
48 using content::BrowserThread;
49
50 namespace shell_integration {
51
52 namespace {
53
54 // TODO(crbug.com/773563): Remove |g_sequenced_task_runner| and use an instance
55 // field / singleton instead.
56 #if BUILDFLAG(IS_WIN)
57 base::LazyThreadPoolCOMSTATaskRunner g_sequenced_task_runner =
58     LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
59         base::TaskTraits(base::MayBlock()),
60         base::SingleThreadTaskRunnerThreadMode::SHARED);
61 #else
62 base::LazyThreadPoolSequencedTaskRunner g_sequenced_task_runner =
63     LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
64         base::TaskTraits(base::MayBlock()));
65 #endif
66
67 bool IsValidDefaultWebClientState(DefaultWebClientState state) {
68   switch (state) {
69     case NOT_DEFAULT:
70     case IS_DEFAULT:
71     case UNKNOWN_DEFAULT:
72     case OTHER_MODE_IS_DEFAULT:
73       return true;
74     case NUM_DEFAULT_STATES:
75       break;
76   }
77   NOTREACHED();
78   return false;
79 }
80
81 void RunCallback(DefaultWebClientWorkerCallback callback,
82                  DefaultWebClientState state) {
83   if (!callback.is_null() && IsValidDefaultWebClientState(state)) {
84     std::move(callback).Run(state);
85     return;
86   }
87 }
88
89 DefaultWebClientSetPermission GetDefaultWebClientSetPermission(
90     internal::WebClientSetMethod method) {
91 #if BUILDFLAG(CHROME_FOR_TESTING)
92   return SET_DEFAULT_NOT_ALLOWED;
93 #else
94   return internal::GetPlatformSpecificDefaultWebClientSetPermission(method);
95 #endif
96 }
97
98 }  // namespace
99
100 DefaultWebClientSetPermission GetDefaultBrowserSetPermission() {
101   return GetDefaultWebClientSetPermission(
102       internal::WebClientSetMethod::kDefaultBrowser);
103 }
104
105 DefaultWebClientSetPermission GetDefaultSchemeClientSetPermission() {
106   return GetDefaultWebClientSetPermission(
107       internal::WebClientSetMethod::kDefaultSchemeHandler);
108 }
109
110 bool CanSetAsDefaultBrowser() {
111   return GetDefaultBrowserSetPermission() != SET_DEFAULT_NOT_ALLOWED;
112 }
113
114 base::CommandLine CommandLineArgsForLauncher(
115     const GURL& url,
116     const std::string& extension_app_id,
117     const base::FilePath& profile_path,
118     const std::string& run_on_os_login_mode) {
119   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
120                                                 base::BlockingType::MAY_BLOCK);
121   base::CommandLine new_cmd_line(base::CommandLine::NO_PROGRAM);
122
123   AppendProfileArgs(
124       extension_app_id.empty() ? base::FilePath() : profile_path,
125       &new_cmd_line);
126
127   // If |extension_app_id| is present, we use the kAppId switch rather than
128   // the kApp switch (the launch url will be read from the extension app
129   // during launch.
130   if (!extension_app_id.empty()) {
131     new_cmd_line.AppendSwitchASCII(switches::kAppId, extension_app_id);
132   } else {
133     // Use '--app=url' instead of just 'url' to launch the browser with minimal
134     // chrome.
135     // Note: Do not change this flag!  Old Gears shortcuts will break if you do!
136     new_cmd_line.AppendSwitchASCII(switches::kApp, url.spec());
137   }
138
139   if (!run_on_os_login_mode.empty()) {
140     new_cmd_line.AppendSwitchASCII(switches::kAppRunOnOsLoginMode,
141                                    run_on_os_login_mode);
142   }
143
144   return new_cmd_line;
145 }
146
147 void AppendProfileArgs(const base::FilePath& profile_path,
148                        base::CommandLine* command_line) {
149   DCHECK(command_line);
150   const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
151
152   // Use the same UserDataDir for new launches that we currently have set.
153   base::FilePath user_data_dir =
154       cmd_line.GetSwitchValuePath(switches::kUserDataDir);
155 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
156   policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
157 #endif
158   if (!user_data_dir.empty()) {
159     // Make sure user_data_dir is an absolute path.
160     user_data_dir = base::MakeAbsoluteFilePath(user_data_dir);
161     if (!user_data_dir.empty() && base::PathExists(user_data_dir))
162       command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
163   }
164
165 #if BUILDFLAG(IS_CHROMEOS_ASH)
166   base::FilePath profile =
167       cmd_line.GetSwitchValuePath(ash::switches::kLoginProfile);
168   if (!profile.empty())
169     command_line->AppendSwitchPath(ash::switches::kLoginProfile, profile);
170 #else
171   if (!profile_path.empty())
172     command_line->AppendSwitchPath(switches::kProfileDirectory,
173                                    profile_path.BaseName());
174 #endif
175 }
176
177 #if !BUILDFLAG(IS_WIN)
178 std::u16string GetAppShortcutsSubdirName() {
179   if (chrome::GetChannel() == version_info::Channel::CANARY)
180     return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY);
181   return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME);
182 }
183 #endif  // !BUILDFLAG(IS_WIN)
184
185 ///////////////////////////////////////////////////////////////////////////////
186 // DefaultWebClientWorker
187 //
188
189 void DefaultWebClientWorker::StartCheckIsDefault(
190     DefaultWebClientWorkerCallback callback) {
191   g_sequenced_task_runner.Get()->PostTask(
192       FROM_HERE, base::BindOnce(&DefaultWebClientWorker::CheckIsDefault, this,
193                                 false, std::move(callback)));
194 }
195
196 void DefaultWebClientWorker::StartSetAsDefault(
197     DefaultWebClientWorkerCallback callback) {
198   g_sequenced_task_runner.Get()->PostTask(
199       FROM_HERE, base::BindOnce(&DefaultWebClientWorker::SetAsDefault, this,
200                                 std::move(callback)));
201 }
202
203 ///////////////////////////////////////////////////////////////////////////////
204 // DefaultWebClientWorker, protected:
205
206 DefaultWebClientWorker::DefaultWebClientWorker(const char* worker_name)
207     : worker_name_(worker_name) {}
208
209 DefaultWebClientWorker::~DefaultWebClientWorker() = default;
210
211 void DefaultWebClientWorker::OnCheckIsDefaultComplete(
212     DefaultWebClientState state,
213     bool is_following_set_as_default,
214     DefaultWebClientWorkerCallback callback) {
215   DCHECK_CURRENTLY_ON(BrowserThread::UI);
216   RunCallback(std::move(callback), state);
217
218   if (is_following_set_as_default)
219     ReportSetDefaultResult(state);
220 }
221
222 ///////////////////////////////////////////////////////////////////////////////
223 // DefaultWebClientWorker, private:
224
225 void DefaultWebClientWorker::CheckIsDefault(
226     bool is_following_set_as_default,
227     DefaultWebClientWorkerCallback callback) {
228   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
229                                                 base::BlockingType::MAY_BLOCK);
230
231   DefaultWebClientState state = CheckIsDefaultImpl();
232   content::GetUIThreadTaskRunner({})->PostTask(
233       FROM_HERE,
234       base::BindOnce(&DefaultBrowserWorker::OnCheckIsDefaultComplete, this,
235                      state, is_following_set_as_default, std::move(callback)));
236 }
237
238 void DefaultWebClientWorker::SetAsDefault(
239     DefaultWebClientWorkerCallback callback) {
240   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
241                                                 base::BlockingType::MAY_BLOCK);
242
243   // SetAsDefaultImpl will make sure the callback is executed exactly once.
244   SetAsDefaultImpl(base::BindOnce(&DefaultWebClientWorker::CheckIsDefault, this,
245                                   true, std::move(callback)));
246 }
247
248 void DefaultWebClientWorker::ReportSetDefaultResult(
249     DefaultWebClientState state) {
250   base::LinearHistogram::FactoryGet(
251       base::StringPrintf("%s.SetDefaultResult2", worker_name_), 1,
252       DefaultWebClientState::NUM_DEFAULT_STATES,
253       DefaultWebClientState::NUM_DEFAULT_STATES + 1,
254       base::HistogramBase::kUmaTargetedHistogramFlag)
255       ->Add(state);
256 }
257
258 ///////////////////////////////////////////////////////////////////////////////
259 // DefaultBrowserWorker
260 //
261
262 DefaultBrowserWorker::DefaultBrowserWorker()
263     : DefaultWebClientWorker("DefaultBrowser") {}
264
265 ///////////////////////////////////////////////////////////////////////////////
266 // DefaultBrowserWorker, private:
267
268 DefaultBrowserWorker::~DefaultBrowserWorker() = default;
269
270 DefaultWebClientState DefaultBrowserWorker::CheckIsDefaultImpl() {
271   return GetDefaultBrowser();
272 }
273
274 void DefaultBrowserWorker::SetAsDefaultImpl(
275     base::OnceClosure on_finished_callback) {
276   switch (GetDefaultBrowserSetPermission()) {
277     case SET_DEFAULT_NOT_ALLOWED:
278       // This is a no-op on channels where set-default is not allowed, but not
279       // an error.
280       break;
281     case SET_DEFAULT_UNATTENDED:
282       SetAsDefaultBrowser();
283       break;
284     case SET_DEFAULT_INTERACTIVE:
285 #if BUILDFLAG(IS_WIN)
286       if (interactive_permitted_) {
287         win::SetAsDefaultBrowserUsingSystemSettings(
288             std::move(on_finished_callback));
289         // Early return because the function above takes care of calling
290         // `on_finished_callback`.
291         return;
292       }
293 #endif  // BUILDFLAG(IS_WIN)
294       break;
295   }
296   std::move(on_finished_callback).Run();
297 }
298
299 ///////////////////////////////////////////////////////////////////////////////
300 // DefaultSchemeClientWorker
301 //
302
303 DefaultSchemeClientWorker::DefaultSchemeClientWorker(const std::string& scheme)
304     : DefaultWebClientWorker("DefaultSchemeClient"), scheme_(scheme) {}
305
306 DefaultSchemeClientWorker::DefaultSchemeClientWorker(const GURL& url)
307     : DefaultWebClientWorker("DefaultSchemeClient"),
308       scheme_(url.scheme()),
309       url_(url) {}
310
311 void DefaultSchemeClientWorker::StartCheckIsDefaultAndGetDefaultClientName(
312     DefaultSchemeHandlerWorkerCallback callback) {
313   g_sequenced_task_runner.Get()->PostTask(
314       FROM_HERE,
315       base::BindOnce(
316           &DefaultSchemeClientWorker::CheckIsDefaultAndGetDefaultClientName,
317           this, std::move(callback)));
318 }
319
320 ///////////////////////////////////////////////////////////////////////////////
321 // DefaultSchemeClientWorker, protected:
322
323 DefaultSchemeClientWorker::~DefaultSchemeClientWorker() = default;
324
325 void DefaultSchemeClientWorker::OnCheckIsDefaultAndGetDefaultClientNameComplete(
326     DefaultWebClientState state,
327     std::u16string program_name,
328     DefaultSchemeHandlerWorkerCallback callback) {
329   DCHECK_CURRENTLY_ON(BrowserThread::UI);
330
331   if (!callback.is_null() && IsValidDefaultWebClientState(state)) {
332     std::move(callback).Run(state, program_name);
333   }
334 }
335
336 ///////////////////////////////////////////////////////////////////////////////
337 // DefaultSchemeClientWorker, private:
338
339 void DefaultSchemeClientWorker::CheckIsDefaultAndGetDefaultClientName(
340     DefaultSchemeHandlerWorkerCallback callback) {
341   DCHECK(!url_.is_empty());
342   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
343                                                 base::BlockingType::MAY_BLOCK);
344
345   DefaultWebClientState state = CheckIsDefaultImpl();
346   std::u16string program_name = GetDefaultClientNameImpl();
347   content::GetUIThreadTaskRunner({})->PostTask(
348       FROM_HERE,
349       base::BindOnce(&DefaultSchemeClientWorker::
350                          OnCheckIsDefaultAndGetDefaultClientNameComplete,
351                      this, state, program_name, std::move(callback)));
352 }
353
354 DefaultWebClientState DefaultSchemeClientWorker::CheckIsDefaultImpl() {
355   return IsDefaultClientForScheme(scheme_);
356 }
357
358 std::u16string DefaultSchemeClientWorker::GetDefaultClientNameImpl() {
359   return GetApplicationNameForScheme(url_);
360 }
361
362 void DefaultSchemeClientWorker::SetAsDefaultImpl(
363     base::OnceClosure on_finished_callback) {
364   switch (GetDefaultSchemeClientSetPermission()) {
365     case SET_DEFAULT_NOT_ALLOWED:
366       // Not allowed, do nothing.
367       break;
368     case SET_DEFAULT_UNATTENDED:
369       SetAsDefaultClientForScheme(scheme_);
370       break;
371     case SET_DEFAULT_INTERACTIVE:
372 #if BUILDFLAG(IS_WIN)
373       if (interactive_permitted_) {
374         win::SetAsDefaultClientForSchemeUsingSystemSettings(
375             scheme_, std::move(on_finished_callback));
376         // Early return because the function above takes care of calling
377         // `on_finished_callback`.
378         return;
379       }
380 #endif  // BUILDFLAG(IS_WIN)
381       break;
382   }
383   std::move(on_finished_callback).Run();
384 }
385
386 }  // namespace shell_integration