Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(390)

Side by Side Diff: win8/delegate_execute/chrome_util.cc

Issue 10875008: Integrate the Windows 8 code into the Chromium tree. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove conflicting OWNERS file. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « win8/delegate_execute/chrome_util.h ('k') | win8/delegate_execute/command_execute_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "win8/delegate_execute/chrome_util.h"
6
7 #include <atlbase.h>
8 #include <shlobj.h>
9 #include <windows.h>
10
11 #include <algorithm>
12 #include <limits>
13 #include <string>
14
15 #include "base/file_path.h"
16 #include "base/file_util.h"
17 #include "base/md5.h"
18 #include "base/process_util.h"
19 #include "base/string_util.h"
20 #include "base/utf_string_conversions.h"
21 #include "base/win/registry.h"
22 #include "base/win/scoped_comptr.h"
23 #include "base/win/scoped_handle.h"
24 #include "base/win/win_util.h"
25 #include "google_update/google_update_idl.h"
26
27 namespace {
28
29 #if defined(GOOGLE_CHROME_BUILD)
30 const wchar_t kAppUserModelId[] = L"Chrome";
31 #else // GOOGLE_CHROME_BUILD
32 const wchar_t kAppUserModelId[] = L"Chromium";
33 #endif // GOOGLE_CHROME_BUILD
34
35 #if defined(GOOGLE_CHROME_BUILD)
36
37 // TODO(grt): These constants live in installer_util. Consider moving them
38 // into common_constants to allow for reuse.
39 const FilePath::CharType kNewChromeExe[] = FILE_PATH_LITERAL("new_chrome.exe");
40 const wchar_t kRenameCommandValue[] = L"cmd";
41 const wchar_t kChromeAppGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
42 const wchar_t kRegPathChromeClient[] =
43 L"Software\\Google\\Update\\Clients\\"
44 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
45 const int kExitCodeRenameSuccessful = 23;
46
47 // Returns the name of the global event used to detect if |chrome_exe| is in
48 // use by a browser process.
49 // TODO(grt): Move this somewhere central so it can be used by both this
50 // IsBrowserRunning (below) and IsBrowserAlreadyRunning (browser_util_win.cc).
51 string16 GetEventName(const FilePath& chrome_exe) {
52 static wchar_t const kEventPrefix[] = L"Global\\";
53 const size_t prefix_len = arraysize(kEventPrefix) - 1;
54 string16 name;
55 name.reserve(prefix_len + chrome_exe.value().size());
56 name.assign(kEventPrefix, prefix_len);
57 name.append(chrome_exe.value());
58 std::replace(name.begin() + prefix_len, name.end(), '\\', '!');
59 std::transform(name.begin() + prefix_len, name.end(),
60 name.begin() + prefix_len, tolower);
61 return name;
62 }
63
64 // Returns true if |chrome_exe| is in use by a browser process. In this case,
65 // "in use" means past ChromeBrowserMainParts::PreMainMessageLoopRunImpl.
66 bool IsBrowserRunning(const FilePath& chrome_exe) {
67 base::win::ScopedHandle handle(::OpenEvent(
68 SYNCHRONIZE, FALSE, GetEventName(chrome_exe).c_str()));
69 if (handle.IsValid())
70 return true;
71 DWORD last_error = ::GetLastError();
72 if (last_error != ERROR_FILE_NOT_FOUND) {
73 AtlTrace("%hs. Failed to open browser event; error %u.\n", __FUNCTION__,
74 last_error);
75 }
76 return false;
77 }
78
79 // Returns true if the file new_chrome.exe exists in the same directory as
80 // |chrome_exe|.
81 bool NewChromeExeExists(const FilePath& chrome_exe) {
82 FilePath new_chrome_exe(chrome_exe.DirName().Append(kNewChromeExe));
83 return file_util::PathExists(new_chrome_exe);
84 }
85
86 bool GetUpdateCommand(bool is_per_user, string16* update_command) {
87 const HKEY root = is_per_user ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
88 base::win::RegKey key(root, kRegPathChromeClient, KEY_QUERY_VALUE);
89
90 return key.ReadValue(kRenameCommandValue, update_command) == ERROR_SUCCESS;
91 }
92
93 #endif // GOOGLE_CHROME_BUILD
94
95 // TODO(grt): This code also lives in installer_util. Refactor for reuse.
96 bool IsPerUserInstall(const FilePath& chrome_exe) {
97 wchar_t program_files_path[MAX_PATH] = {0};
98 if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
99 SHGFP_TYPE_CURRENT, program_files_path))) {
100 return !StartsWith(chrome_exe.value().c_str(), program_files_path, false);
101 } else {
102 NOTREACHED();
103 }
104 return true;
105 }
106
107 // TODO(gab): This code also lives in shell_util. Refactor for reuse.
108 string16 ByteArrayToBase32(const uint8* bytes, size_t size) {
109 static const char kEncoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
110
111 // Eliminate special cases first.
112 if (size == 0) {
113 return string16();
114 } else if (size == 1) {
115 string16 ret;
116 ret.push_back(kEncoding[(bytes[0] & 0xf8) >> 3]);
117 ret.push_back(kEncoding[(bytes[0] & 0x07) << 2]);
118 return ret;
119 } else if (size >= std::numeric_limits<size_t>::max() / 8) {
120 // If |size| is too big, the calculation of |encoded_length| below will
121 // overflow.
122 AtlTrace("%hs. Byte array is too long.\n", __FUNCTION__);
123 return string16();
124 }
125
126 // Overestimate the number of bits in the string by 4 so that dividing by 5
127 // is the equivalent of rounding up the actual number of bits divided by 5.
128 const size_t encoded_length = (size * 8 + 4) / 5;
129
130 string16 ret;
131 ret.reserve(encoded_length);
132
133 // A bit stream which will be read from the left and appended to from the
134 // right as it's emptied.
135 uint16 bit_stream = (bytes[0] << 8) + bytes[1];
136 size_t next_byte_index = 2;
137 int free_bits = 0;
138 while (free_bits < 16) {
139 // Extract the 5 leftmost bits in the stream
140 ret.push_back(kEncoding[(bit_stream & 0xf800) >> 11]);
141 bit_stream <<= 5;
142 free_bits += 5;
143
144 // If there is enough room in the bit stream, inject another byte (if there
145 // are any left...).
146 if (free_bits >= 8 && next_byte_index < size) {
147 free_bits -= 8;
148 bit_stream += bytes[next_byte_index++] << free_bits;
149 }
150 }
151
152 if (ret.length() != encoded_length) {
153 AtlTrace("%hs. Encoding doesn't match expected length.\n", __FUNCTION__);
154 return string16();
155 }
156 return ret;
157 }
158
159 // TODO(gab): This code also lives in shell_util. Refactor for reuse.
160 bool GetUserSpecificRegistrySuffix(string16* suffix) {
161 string16 user_sid;
162 if (!base::win::GetUserSidString(&user_sid)) {
163 AtlTrace("%hs. GetUserSidString failed.\n", __FUNCTION__);
164 return false;
165 }
166 COMPILE_ASSERT(sizeof(base::MD5Digest) == 16, size_of_MD5_not_as_expected_);
167 base::MD5Digest md5_digest;
168 std::string user_sid_ascii(UTF16ToASCII(user_sid));
169 base::MD5Sum(user_sid_ascii.c_str(), user_sid_ascii.length(), &md5_digest);
170 const string16 base32_md5(
171 ByteArrayToBase32(md5_digest.a, arraysize(md5_digest.a)));
172 // The value returned by the base32 algorithm above must never change and must
173 // always be 26 characters long (i.e. if someone ever moves this to base and
174 // implements the full base32 algorithm (i.e. with appended '=' signs in the
175 // output), they must provide a flag to allow this method to still request
176 // the output with no appended '=' signs).
177 if (base32_md5.length() != 26U) {
178 AtlTrace("%hs. Base32 encoding of md5 hash is incorrect.\n", __FUNCTION__);
179 return false;
180 }
181 suffix->reserve(base32_md5.length() + 1);
182 suffix->assign(1, L'.');
183 suffix->append(base32_md5);
184 return true;
185 }
186
187 } // namespace
188
189 namespace delegate_execute {
190
191 void UpdateChromeIfNeeded(const FilePath& chrome_exe) {
192 #if defined(GOOGLE_CHROME_BUILD)
193 // Nothing to do if a browser is already running or if there's no
194 // new_chrome.exe.
195 if (IsBrowserRunning(chrome_exe) || !NewChromeExeExists(chrome_exe))
196 return;
197
198 base::ProcessHandle process_handle = base::kNullProcessHandle;
199
200 if (IsPerUserInstall(chrome_exe)) {
201 // Read the update command from the registry.
202 string16 update_command;
203 if (!GetUpdateCommand(true, &update_command)) {
204 AtlTrace("%hs. Failed to read update command from registry.\n",
205 __FUNCTION__);
206 } else {
207 // Run the update command.
208 base::LaunchOptions launch_options;
209 launch_options.start_hidden = true;
210 if (!base::LaunchProcess(update_command, launch_options,
211 &process_handle)) {
212 AtlTrace("%hs. Failed to launch command to finalize update; "
213 "error %u.\n", __FUNCTION__, ::GetLastError());
214 process_handle = base::kNullProcessHandle;
215 }
216 }
217 } else {
218 // Run the update command via Google Update.
219 HRESULT hr = S_OK;
220 base::win::ScopedComPtr<IProcessLauncher> process_launcher;
221 hr = process_launcher.CreateInstance(__uuidof(ProcessLauncherClass));
222 if (FAILED(hr)) {
223 AtlTrace("%hs. Failed to Create ProcessLauncher; hr=0x%X.\n",
224 __FUNCTION__, hr);
225 } else {
226 ULONG_PTR handle = 0;
227 hr = process_launcher->LaunchCmdElevated(
228 kChromeAppGuid, kRenameCommandValue, GetCurrentProcessId(), &handle);
229 if (FAILED(hr)) {
230 AtlTrace("%hs. Failed to launch command to finalize update; "
231 "hr=0x%X.\n", __FUNCTION__, hr);
232 } else {
233 process_handle = reinterpret_cast<base::ProcessHandle>(handle);
234 }
235 }
236 }
237
238 // Wait for the update to complete and report the results.
239 if (process_handle != base::kNullProcessHandle) {
240 int exit_code = 0;
241 // WaitForExitCode will close the handle in all cases.
242 if (!base::WaitForExitCode(process_handle, &exit_code)) {
243 AtlTrace("%hs. Failed to get result when finalizing update.\n",
244 __FUNCTION__);
245 } else if (exit_code != kExitCodeRenameSuccessful) {
246 AtlTrace("%hs. Failed to finalize update with exit code %d.\n",
247 __FUNCTION__, exit_code);
248 } else {
249 AtlTrace("%hs. Finalized pending update.\n", __FUNCTION__);
250 }
251 }
252 #endif
253 }
254
255 // TODO(gab): This code also lives in shell_util. Refactor for reuse.
256 string16 GetAppId(const FilePath& chrome_exe) {
257 string16 app_id(kAppUserModelId);
258 string16 suffix;
259 if (IsPerUserInstall(chrome_exe) &&
260 !GetUserSpecificRegistrySuffix(&suffix)) {
261 AtlTrace("%hs. GetUserSpecificRegistrySuffix failed.\n",
262 __FUNCTION__);
263 }
264 return app_id.append(suffix);
265 }
266
267 } // delegate_execute
OLDNEW
« no previous file with comments | « win8/delegate_execute/chrome_util.h ('k') | win8/delegate_execute/command_execute_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698