1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/installer/util/auto_launch_util.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/win_util.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/util_constants.h"
#include "crypto/sha2.h"
using base::ASCIIToUTF16;
namespace auto_launch_util {
// The prefix of the Chrome Auto-launch key under the Run key.
const wchar_t kAutolaunchKeyValue[] = L"GoogleChromeAutoLaunch";
// We use one Run key with flags specifying which feature we want to start up.
// When we change our Run key we need to specify what we want to do with each
// flag. This lists the possible actions we can take with the flags.
enum FlagSetting {
FLAG_DISABLE, // Disable the flag.
FLAG_ENABLE, // Enable the flag.
FLAG_PRESERVE, // Preserve the value that the flag has currently.
};
// A helper function that takes a |profile_directory| and builds a registry key
// name to use when deciding where to read/write the auto-launch value
// to/from. It takes into account the name of the profile (so that different
// installations of Chrome don't conflict, and so the in the future different
// profiles can be auto-launched (or not) separately).
base::string16 ProfileToKeyName(const base::string16& profile_directory) {
base::FilePath path;
const bool success = PathService::Get(chrome::DIR_USER_DATA, &path);
DCHECK(success);
path = path.Append(profile_directory);
std::string input(path.AsUTF8Unsafe());
uint8 hash[16];
crypto::SHA256HashString(input, hash, sizeof(hash));
std::string hash_string = base::HexEncode(hash, sizeof(hash));
return base::string16(kAutolaunchKeyValue) + ASCIIToUTF16("_") +
ASCIIToUTF16(hash_string);
}
// Returns whether the Chrome executable specified in |application_path| is set
// to auto-launch at computer startup with a given |command_line_switch|.
// NOTE: |application_path| is optional and should be blank in most cases (as
// it will default to the application path of the current executable).
// |profile_directory| is the name of the directory (leaf, not the full path)
// that contains the profile that should be opened at computer startup.
// |command_line_switch| is the switch we are optionally interested in and, if
// not blank, must be present for the function to return true. If blank, it acts
// like a wildcard.
bool WillLaunchAtLoginWithSwitch(const base::FilePath& application_path,
const base::string16& profile_directory,
const std::string& command_line_switch) {
base::string16 key_name(ProfileToKeyName(profile_directory));
base::string16 autolaunch;
if (!base::win::ReadCommandFromAutoRun(
HKEY_CURRENT_USER, key_name, &autolaunch)) {
return false;
}
base::FilePath chrome_exe(application_path);
if (chrome_exe.empty()) {
if (!PathService::Get(base::DIR_EXE, &chrome_exe)) {
NOTREACHED();
return false;
}
}
chrome_exe = chrome_exe.Append(installer::kChromeExe);
if (autolaunch.find(chrome_exe.value()) == base::string16::npos)
return false;
return command_line_switch.empty() ||
autolaunch.find(ASCIIToUTF16(command_line_switch)) !=
base::string16::npos;
}
bool AutoStartRequested(const base::string16& profile_directory,
bool window_requested,
const base::FilePath& application_path) {
if (window_requested) {
return WillLaunchAtLoginWithSwitch(application_path,
profile_directory,
switches::kAutoLaunchAtStartup);
} else {
// Background mode isn't profile specific, but is attached to the Run key
// for the Default profile.
return WillLaunchAtLoginWithSwitch(application_path,
ASCIIToUTF16(chrome::kInitialProfile),
switches::kNoStartupWindow);
}
}
bool CheckAndRemoveDeprecatedBackgroundModeSwitch() {
// For backwards compatibility we need to provide a migration path from the
// previously used key "chromium" that the BackgroundMode used to set, as it
// is incompatible with the new key (can't have two Run keys with
// conflicting switches).
base::string16 chromium = ASCIIToUTF16("chromium");
base::string16 value;
if (base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER, chromium, &value)) {
if (value.find(ASCIIToUTF16(switches::kNoStartupWindow)) !=
base::string16::npos) {
base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, chromium);
return true;
}
}
return false;
}
void SetWillLaunchAtLogin(const base::FilePath& application_path,
const base::string16& profile_directory,
FlagSetting foreground_mode,
FlagSetting background_mode) {
if (CheckAndRemoveDeprecatedBackgroundModeSwitch()) {
// We've found the deprecated switch, we must migrate it (unless background
// mode is being turned off).
if (profile_directory == ASCIIToUTF16(chrome::kInitialProfile) &&
background_mode == FLAG_PRESERVE) {
// Preserve in this case also covers the deprecated value, so we must
// explicitly turn the flag on and the rest will be taken care of below.
background_mode = FLAG_ENABLE;
} else {
// When we add support for multiple profiles for foreground mode we need
// to think about where to store the background mode switch. I think we
// need to store it with the Default profile (call SetWillLaunchAtLogin
// again specifying the Default profile), but concerns were raised in
// review.
NOTREACHED();
}
}
base::string16 key_name(ProfileToKeyName(profile_directory));
// Check which feature should be enabled.
bool in_foreground =
foreground_mode == FLAG_ENABLE ||
(foreground_mode == FLAG_PRESERVE &&
WillLaunchAtLoginWithSwitch(application_path,
profile_directory,
switches::kAutoLaunchAtStartup));
bool in_background =
background_mode == FLAG_ENABLE ||
(background_mode == FLAG_PRESERVE &&
WillLaunchAtLoginWithSwitch(application_path,
profile_directory,
switches::kNoStartupWindow));
// TODO(finnur): Convert this into a shortcut, instead of using the Run key.
if (in_foreground || in_background) {
base::FilePath path(application_path);
if (path.empty()) {
if (!PathService::Get(base::DIR_EXE, &path)) {
NOTREACHED();
return;
}
}
base::string16 cmd_line = ASCIIToUTF16("\"");
cmd_line += path.value();
cmd_line += ASCIIToUTF16("\\");
cmd_line += installer::kChromeExe;
cmd_line += ASCIIToUTF16("\"");
if (in_background) {
cmd_line += ASCIIToUTF16(" --");
cmd_line += ASCIIToUTF16(switches::kNoStartupWindow);
}
if (in_foreground) {
cmd_line += ASCIIToUTF16(" --");
cmd_line += ASCIIToUTF16(switches::kAutoLaunchAtStartup);
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
// Propagate --user-data-dir if it was specified on the command line.
// Retrieve the value from the PathService since some sanitation may have
// taken place. There is no need to add it to the command line in the
// event that the dir was overridden by Group Policy since the GP override
// will be in force when Chrome is launched.
if (command_line.HasSwitch(switches::kUserDataDir)) {
cmd_line += ASCIIToUTF16(" --");
cmd_line += ASCIIToUTF16(switches::kUserDataDir);
cmd_line += ASCIIToUTF16("=\"");
base::FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
cmd_line += user_data_dir.value();
cmd_line += ASCIIToUTF16("\"");
}
cmd_line += ASCIIToUTF16(" --");
cmd_line += ASCIIToUTF16(switches::kProfileDirectory);
cmd_line += ASCIIToUTF16("=\"");
cmd_line += profile_directory;
cmd_line += ASCIIToUTF16("\"");
}
base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, key_name, cmd_line);
} else {
base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, key_name);
}
}
void DisableAllAutoStartFeatures(const base::string16& profile_directory) {
DisableForegroundStartAtLogin(profile_directory);
DisableBackgroundStartAtLogin();
}
void EnableForegroundStartAtLogin(const base::string16& profile_directory,
const base::FilePath& application_path) {
SetWillLaunchAtLogin(
application_path, profile_directory, FLAG_ENABLE, FLAG_PRESERVE);
}
void DisableForegroundStartAtLogin(const base::string16& profile_directory) {
SetWillLaunchAtLogin(
base::FilePath(), profile_directory, FLAG_DISABLE, FLAG_PRESERVE);
}
void EnableBackgroundStartAtLogin() {
// Background mode isn't profile specific, but we specify the Default profile
// just to have a unique Run key to attach it to. FilePath is blank because
// this function is not called from the installer (see comments for
// EnableAutoStartAtLogin).
SetWillLaunchAtLogin(base::FilePath(),
ASCIIToUTF16(chrome::kInitialProfile),
FLAG_PRESERVE,
FLAG_ENABLE);
}
void DisableBackgroundStartAtLogin() {
SetWillLaunchAtLogin(base::FilePath(),
ASCIIToUTF16(chrome::kInitialProfile),
FLAG_PRESERVE,
FLAG_DISABLE);
}
} // namespace auto_launch_util
|