857f8e02bf5c6cf295cbe4cc6d098071d85c37cd
[platform/framework/web/crosswalk.git] / src / chrome / installer / util / auto_launch_util.cc
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.
4
5 #include "chrome/installer/util/auto_launch_util.h"
6
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"
21
22 using base::ASCIIToUTF16;
23 using base::ASCIIToWide;
24
25 namespace auto_launch_util {
26
27 // The prefix of the Chrome Auto-launch key under the Run key.
28 const wchar_t kAutolaunchKeyValue[] = L"GoogleChromeAutoLaunch";
29
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.
33 enum FlagSetting {
34   FLAG_DISABLE,   // Disable the flag.
35   FLAG_ENABLE,    // Enable the flag.
36   FLAG_PRESERVE,  // Preserve the value that the flag has currently.
37 };
38
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) {
45   base::FilePath path;
46   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
47   if (command_line.HasSwitch(switches::kUserDataDir)) {
48     path = command_line.GetSwitchValuePath(switches::kUserDataDir);
49   } else {
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];
60   }
61   path = path.Append(profile_directory);
62
63   std::string input(path.AsUTF8Unsafe());
64   uint8 hash[16];
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);
69 }
70
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
79 // like a wildcard.
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)) {
87     return false;
88   }
89
90   base::FilePath chrome_exe(application_path);
91   if (chrome_exe.empty()) {
92     if (!PathService::Get(base::DIR_EXE, &chrome_exe)) {
93       NOTREACHED();
94       return false;
95     }
96   }
97   chrome_exe = chrome_exe.Append(installer::kChromeExe);
98
99   if (autolaunch.find(chrome_exe.value()) == base::string16::npos)
100     return false;
101
102   return command_line_switch.empty() ||
103          autolaunch.find(ASCIIToUTF16(command_line_switch)) !=
104              base::string16::npos;
105 }
106
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,
112                                        profile_directory,
113                                        switches::kAutoLaunchAtStartup);
114   } else {
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);
120   }
121 }
122
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);
134       return true;
135     }
136   }
137
138   return false;
139 }
140
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;
153     } else {
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
158       // review.
159       NOTREACHED();
160     }
161   }
162   base::string16 key_name(ProfileToKeyName(profile_directory));
163
164   // Check which feature should be enabled.
165   bool in_foreground =
166       foreground_mode == FLAG_ENABLE ||
167       (foreground_mode == FLAG_PRESERVE &&
168           WillLaunchAtLoginWithSwitch(application_path,
169                                       profile_directory,
170                                       switches::kAutoLaunchAtStartup));
171   bool in_background =
172       background_mode == FLAG_ENABLE ||
173       (background_mode == FLAG_PRESERVE &&
174           WillLaunchAtLoginWithSwitch(application_path,
175                                       profile_directory,
176                                       switches::kNoStartupWindow));
177
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);
181     if (path.empty()) {
182       if (!PathService::Get(base::DIR_EXE, &path)) {
183         NOTREACHED();
184         return;
185       }
186     }
187     base::string16 cmd_line = ASCIIToUTF16("\"");
188     cmd_line += path.value();
189     cmd_line += ASCIIToUTF16("\\");
190     cmd_line += installer::kChromeExe;
191     cmd_line += ASCIIToUTF16("\"");
192
193     if (in_background) {
194       cmd_line += ASCIIToUTF16(" --");
195       cmd_line += ASCIIToUTF16(switches::kNoStartupWindow);
196     }
197     if (in_foreground) {
198       cmd_line += ASCIIToUTF16(" --");
199       cmd_line += ASCIIToUTF16(switches::kAutoLaunchAtStartup);
200
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("=\"");
206         cmd_line +=
207             command_line.GetSwitchValuePath(switches::kUserDataDir).value();
208         cmd_line += ASCIIToUTF16("\"");
209       }
210
211       cmd_line += ASCIIToUTF16(" --");
212       cmd_line += ASCIIToUTF16(switches::kProfileDirectory);
213       cmd_line += ASCIIToUTF16("=\"");
214       cmd_line += profile_directory;
215       cmd_line += ASCIIToUTF16("\"");
216     }
217
218     base::win::AddCommandToAutoRun(
219         HKEY_CURRENT_USER, key_name, cmd_line);
220   } else {
221     base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, key_name);
222   }
223 }
224
225 void DisableAllAutoStartFeatures(const base::string16& profile_directory) {
226   DisableForegroundStartAtLogin(profile_directory);
227   DisableBackgroundStartAtLogin();
228 }
229
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);
234 }
235
236 void DisableForegroundStartAtLogin(const base::string16& profile_directory) {
237   SetWillLaunchAtLogin(
238       base::FilePath(), profile_directory, FLAG_DISABLE, FLAG_PRESERVE);
239 }
240
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),
248                        FLAG_PRESERVE,
249                        FLAG_ENABLE);
250 }
251
252 void DisableBackgroundStartAtLogin() {
253   SetWillLaunchAtLogin(base::FilePath(),
254                        ASCIIToUTF16(chrome::kInitialProfile),
255                        FLAG_PRESERVE,
256                        FLAG_DISABLE);
257 }
258
259 }  // namespace auto_launch_util