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
3 // found in the LICENSE file.
5 #include "chrome/installer/util/auto_launch_util.h"
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "base/path_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/win/win_util.h"
14 #include "chrome/common/chrome_constants.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/chrome_version_info.h"
17 #include "chrome/installer/util/browser_distribution.h"
18 #include "chrome/installer/util/product.h"
19 #include "chrome/installer/util/util_constants.h"
20 #include "crypto/sha2.h"
22 using base::ASCIIToUTF16
;
23 using base::ASCIIToWide
;
25 namespace auto_launch_util
{
27 // The prefix of the Chrome Auto-launch key under the Run key.
28 const wchar_t kAutolaunchKeyValue
[] = L
"GoogleChromeAutoLaunch";
30 // We use one Run key with flags specifying which feature we want to start up.
31 // When we change our Run key we need to specify what we want to do with each
32 // flag. This lists the possible actions we can take with the flags.
34 FLAG_DISABLE
, // Disable the flag.
35 FLAG_ENABLE
, // Enable the flag.
36 FLAG_PRESERVE
, // Preserve the value that the flag has currently.
39 // A helper function that takes a |profile_path| and builds a registry key
40 // name to use when deciding where to read/write the auto-launch value
41 // to/from. It takes into account the name of the profile (so that different
42 // installations of Chrome don't conflict, and so the in the future different
43 // profiles can be auto-launched (or not) separately).
44 base::string16
ProfileToKeyName(const base::string16
& profile_directory
) {
46 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
47 if (command_line
.HasSwitch(switches::kUserDataDir
)) {
48 path
= command_line
.GetSwitchValuePath(switches::kUserDataDir
);
50 // Get the path from the same source as the installer, to make sure there
51 // are no differences.
52 BrowserDistribution
* distribution
=
53 BrowserDistribution::GetSpecificDistribution(
54 BrowserDistribution::CHROME_BROWSER
);
55 installer::Product
product(distribution
);
56 std::vector
<base::FilePath
> data_dir_paths
;
57 product
.GetUserDataPaths(&data_dir_paths
);
58 if (!data_dir_paths
.empty())
59 path
= data_dir_paths
[0];
61 path
= path
.Append(profile_directory
);
63 std::string
input(path
.AsUTF8Unsafe());
65 crypto::SHA256HashString(input
, hash
, sizeof(hash
));
66 std::string hash_string
= base::HexEncode(hash
, sizeof(hash
));
67 return base::string16(kAutolaunchKeyValue
) + ASCIIToWide("_") +
68 ASCIIToWide(hash_string
);
71 // Returns whether the Chrome executable specified in |application_path| is set
72 // to auto-launch at computer startup with a given |command_line_switch|.
73 // NOTE: |application_path| is optional and should be blank in most cases (as
74 // it will default to the application path of the current executable).
75 // |profile_directory| is the name of the directory (leaf, not the full path)
76 // that contains the profile that should be opened at computer startup.
77 // |command_line_switch| is the switch we are optionally interested in and, if
78 // not blank, must be present for the function to return true. If blank, it acts
80 bool WillLaunchAtLoginWithSwitch(const base::FilePath
& application_path
,
81 const base::string16
& profile_directory
,
82 const std::string
& command_line_switch
) {
83 base::string16
key_name(ProfileToKeyName(profile_directory
));
84 base::string16 autolaunch
;
85 if (!base::win::ReadCommandFromAutoRun(
86 HKEY_CURRENT_USER
, key_name
, &autolaunch
)) {
90 base::FilePath
chrome_exe(application_path
);
91 if (chrome_exe
.empty()) {
92 if (!PathService::Get(base::DIR_EXE
, &chrome_exe
)) {
97 chrome_exe
= chrome_exe
.Append(installer::kChromeExe
);
99 if (autolaunch
.find(chrome_exe
.value()) == base::string16::npos
)
102 return command_line_switch
.empty() ||
103 autolaunch
.find(ASCIIToUTF16(command_line_switch
)) !=
104 base::string16::npos
;
107 bool AutoStartRequested(const base::string16
& profile_directory
,
108 bool window_requested
,
109 const base::FilePath
& application_path
) {
110 if (window_requested
) {
111 return WillLaunchAtLoginWithSwitch(application_path
,
113 switches::kAutoLaunchAtStartup
);
115 // Background mode isn't profile specific, but is attached to the Run key
116 // for the Default profile.
117 return WillLaunchAtLoginWithSwitch(application_path
,
118 ASCIIToUTF16(chrome::kInitialProfile
),
119 switches::kNoStartupWindow
);
123 bool CheckAndRemoveDeprecatedBackgroundModeSwitch() {
124 // For backwards compatibility we need to provide a migration path from the
125 // previously used key "chromium" that the BackgroundMode used to set, as it
126 // is incompatible with the new key (can't have two Run keys with
127 // conflicting switches).
128 base::string16 chromium
= ASCIIToUTF16("chromium");
129 base::string16 value
;
130 if (base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER
, chromium
, &value
)) {
131 if (value
.find(ASCIIToUTF16(switches::kNoStartupWindow
)) !=
132 base::string16::npos
) {
133 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER
, chromium
);
141 void SetWillLaunchAtLogin(const base::FilePath
& application_path
,
142 const base::string16
& profile_directory
,
143 FlagSetting foreground_mode
,
144 FlagSetting background_mode
) {
145 if (CheckAndRemoveDeprecatedBackgroundModeSwitch()) {
146 // We've found the deprecated switch, we must migrate it (unless background
147 // mode is being turned off).
148 if (profile_directory
== ASCIIToUTF16(chrome::kInitialProfile
) &&
149 background_mode
== FLAG_PRESERVE
) {
150 // Preserve in this case also covers the deprecated value, so we must
151 // explicitly turn the flag on and the rest will be taken care of below.
152 background_mode
= FLAG_ENABLE
;
154 // When we add support for multiple profiles for foreground mode we need
155 // to think about where to store the background mode switch. I think we
156 // need to store it with the Default profile (call SetWillLaunchAtLogin
157 // again specifying the Default profile), but concerns were raised in
162 base::string16
key_name(ProfileToKeyName(profile_directory
));
164 // Check which feature should be enabled.
166 foreground_mode
== FLAG_ENABLE
||
167 (foreground_mode
== FLAG_PRESERVE
&&
168 WillLaunchAtLoginWithSwitch(application_path
,
170 switches::kAutoLaunchAtStartup
));
172 background_mode
== FLAG_ENABLE
||
173 (background_mode
== FLAG_PRESERVE
&&
174 WillLaunchAtLoginWithSwitch(application_path
,
176 switches::kNoStartupWindow
));
178 // TODO(finnur): Convert this into a shortcut, instead of using the Run key.
179 if (in_foreground
|| in_background
) {
180 base::FilePath
path(application_path
);
182 if (!PathService::Get(base::DIR_EXE
, &path
)) {
187 base::string16 cmd_line
= ASCIIToUTF16("\"");
188 cmd_line
+= path
.value();
189 cmd_line
+= ASCIIToUTF16("\\");
190 cmd_line
+= installer::kChromeExe
;
191 cmd_line
+= ASCIIToUTF16("\"");
194 cmd_line
+= ASCIIToUTF16(" --");
195 cmd_line
+= ASCIIToUTF16(switches::kNoStartupWindow
);
198 cmd_line
+= ASCIIToUTF16(" --");
199 cmd_line
+= ASCIIToUTF16(switches::kAutoLaunchAtStartup
);
201 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
202 if (command_line
.HasSwitch(switches::kUserDataDir
)) {
203 cmd_line
+= ASCIIToUTF16(" --");
204 cmd_line
+= ASCIIToUTF16(switches::kUserDataDir
);
205 cmd_line
+= ASCIIToUTF16("=\"");
207 command_line
.GetSwitchValuePath(switches::kUserDataDir
).value();
208 cmd_line
+= ASCIIToUTF16("\"");
211 cmd_line
+= ASCIIToUTF16(" --");
212 cmd_line
+= ASCIIToUTF16(switches::kProfileDirectory
);
213 cmd_line
+= ASCIIToUTF16("=\"");
214 cmd_line
+= profile_directory
;
215 cmd_line
+= ASCIIToUTF16("\"");
218 base::win::AddCommandToAutoRun(
219 HKEY_CURRENT_USER
, key_name
, cmd_line
);
221 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER
, key_name
);
225 void DisableAllAutoStartFeatures(const base::string16
& profile_directory
) {
226 DisableForegroundStartAtLogin(profile_directory
);
227 DisableBackgroundStartAtLogin();
230 void EnableForegroundStartAtLogin(const base::string16
& profile_directory
,
231 const base::FilePath
& application_path
) {
232 SetWillLaunchAtLogin(
233 application_path
, profile_directory
, FLAG_ENABLE
, FLAG_PRESERVE
);
236 void DisableForegroundStartAtLogin(const base::string16
& profile_directory
) {
237 SetWillLaunchAtLogin(
238 base::FilePath(), profile_directory
, FLAG_DISABLE
, FLAG_PRESERVE
);
241 void EnableBackgroundStartAtLogin() {
242 // Background mode isn't profile specific, but we specify the Default profile
243 // just to have a unique Run key to attach it to. FilePath is blank because
244 // this function is not called from the installer (see comments for
245 // EnableAutoStartAtLogin).
246 SetWillLaunchAtLogin(base::FilePath(),
247 ASCIIToUTF16(chrome::kInitialProfile
),
252 void DisableBackgroundStartAtLogin() {
253 SetWillLaunchAtLogin(base::FilePath(),
254 ASCIIToUTF16(chrome::kInitialProfile
),
259 } // namespace auto_launch_util