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

Side by Side Diff: chrome/browser/google/google_update_win.cc

Issue 2176123002: Fix a threading issue and modernize the use of scoped_refptr in the on-demand update checker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 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
« no previous file with comments | « chrome/browser/google/google_update_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/google/google_update_win.h" 5 #include "chrome/browser/google/google_update_win.h"
6 6
7 #include <atlbase.h> 7 #include <atlbase.h>
8 #include <atlcom.h> 8 #include <atlcom.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 #include <string.h> 10 #include <string.h>
11 11
12 #include <utility>
12 #include <vector> 13 #include <vector>
13 14
14 #include "base/bind.h" 15 #include "base/bind.h"
15 #include "base/callback.h" 16 #include "base/callback.h"
16 #include "base/files/file_path.h" 17 #include "base/files/file_path.h"
17 #include "base/location.h" 18 #include "base/location.h"
18 #include "base/macros.h" 19 #include "base/macros.h"
19 #include "base/metrics/histogram.h" 20 #include "base/metrics/histogram.h"
20 #include "base/metrics/sparse_histogram.h" 21 #include "base/metrics/sparse_histogram.h"
21 #include "base/path_service.h" 22 #include "base/path_service.h"
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 205
205 // UpdateCheckDriver ----------------------------------------------------------- 206 // UpdateCheckDriver -----------------------------------------------------------
206 207
207 // A driver that is created and destroyed on the caller's thread and drives 208 // A driver that is created and destroyed on the caller's thread and drives
208 // Google Update on another. 209 // Google Update on another.
209 class UpdateCheckDriver { 210 class UpdateCheckDriver {
210 public: 211 public:
211 // Runs an update check on |task_runner|, invoking methods of |delegate| on 212 // Runs an update check on |task_runner|, invoking methods of |delegate| on
212 // the caller's thread to report progress and final results. 213 // the caller's thread to report progress and final results.
213 static void RunUpdateCheck( 214 static void RunUpdateCheck(
214 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 215 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
215 const std::string& locale, 216 const std::string& locale,
216 bool install_update_if_possible, 217 bool install_update_if_possible,
217 gfx::AcceleratedWidget elevation_window, 218 gfx::AcceleratedWidget elevation_window,
218 const base::WeakPtr<UpdateCheckDelegate>& delegate); 219 const base::WeakPtr<UpdateCheckDelegate>& delegate);
219 220
220 private: 221 private:
221 friend class base::DeleteHelper<UpdateCheckDriver>; 222 friend class base::DeleteHelper<UpdateCheckDriver>;
222 223
223 UpdateCheckDriver( 224 UpdateCheckDriver(
224 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 225 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
225 const std::string& locale, 226 const std::string& locale,
226 bool install_update_if_possible, 227 bool install_update_if_possible,
227 gfx::AcceleratedWidget elevation_window, 228 gfx::AcceleratedWidget elevation_window,
228 const base::WeakPtr<UpdateCheckDelegate>& delegate); 229 const base::WeakPtr<UpdateCheckDelegate>& delegate);
229 230
230 // Invokes a completion or error method on all delegates, as appropriate. 231 // Invokes a completion or error method on all delegates, as appropriate.
231 ~UpdateCheckDriver(); 232 ~UpdateCheckDriver();
232 233
234 // If an UpdateCheckDriver is already running, the delegate is added to the
235 // existing one instead of creating a new one.
236 void AddDelegate(const base::WeakPtr<UpdateCheckDelegate>& delegate);
237
238 // Notifies delegates of an update's progress. |progress|, a number between 0
239 // and 100 (inclusive), is an estimation as to what percentage of the upgrade
240 // has completed. |new_version| indicates the version that is being download
241 // and installed.
242 void NotifyUpgradeProgress(int progress, const base::string16& new_version);
243
233 // Starts an update check. 244 // Starts an update check.
234 void BeginUpdateCheck(); 245 void BeginUpdateCheck();
235 246
236 // Returns the result of initiating an update check. Sets |error_code| if the 247 // Returns the result of initiating an update check. Sets |error_code| if the
237 // result is any kind of failure. On failure, the instance is left in a 248 // result is any kind of failure. On failure, the instance is left in a
238 // consistent state so that this method can be invoked later to retry the 249 // consistent state so that this method can be invoked later to retry the
239 // steps that failed. 250 // steps that failed.
240 HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code); 251 HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code);
241 252
242 // Sets status_ to UPGRADE_ERROR, error_code_ to |error_code|, hresult_ to 253 // Sets status_ to UPGRADE_ERROR, error_code_ to |error_code|, hresult_ to
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 base::string16* new_version, 309 base::string16* new_version,
299 int* progress) const; 310 int* progress) const;
300 311
301 // Polls Google Update to determine the state of the ongoing check or 312 // Polls Google Update to determine the state of the ongoing check or
302 // update. If the process has reached a terminal state, this instance will be 313 // update. If the process has reached a terminal state, this instance will be
303 // deleted and the caller will be notified of the final status. Otherwise, the 314 // deleted and the caller will be notified of the final status. Otherwise, the
304 // caller will be notified of the intermediate state (iff it differs from a 315 // caller will be notified of the intermediate state (iff it differs from a
305 // previous notification) and another future poll will be scheduled. 316 // previous notification) and another future poll will be scheduled.
306 void PollGoogleUpdate(); 317 void PollGoogleUpdate();
307 318
308 // If an UpdateCheckDriver is already running, the delegate is added to the 319 // The global driver instance. Accessed only on the caller's thread.
309 // existing one instead of creating a new one.
310 void AddDelegate(const base::WeakPtr<UpdateCheckDelegate>& delegate);
311
312 static UpdateCheckDriver* driver_; 320 static UpdateCheckDriver* driver_;
313 321
314 // The task runner on which the update checks runs. 322 // The task runner on which the update checks runs.
315 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 323 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
316 324
317 // The caller's task runner, on which methods of the |delegates_| will be 325 // The caller's task runner, on which methods of the |delegates_| will be
318 // invoked. 326 // invoked.
319 scoped_refptr<base::SingleThreadTaskRunner> result_runner_; 327 scoped_refptr<base::SingleThreadTaskRunner> result_runner_;
320 328
321 // The UI locale. 329 // The UI locale.
322 std::string locale_; 330 std::string locale_;
323 331
324 // False to only check for an update; true to also install one if available. 332 // False to only check for an update; true to also install one if available.
325 bool install_update_if_possible_; 333 bool install_update_if_possible_;
326 334
327 // A parent window in case any UX is required (e.g., an elevation prompt). 335 // A parent window in case any UX is required (e.g., an elevation prompt).
328 gfx::AcceleratedWidget elevation_window_; 336 gfx::AcceleratedWidget elevation_window_;
329 337
330 // Contains all delegates by which feedback is conveyed. 338 // Contains all delegates by which feedback is conveyed. Accessed only on the
339 // caller's thread.
331 std::vector<base::WeakPtr<UpdateCheckDelegate>> delegates_; 340 std::vector<base::WeakPtr<UpdateCheckDelegate>> delegates_;
332 341
333 // Number of remaining retries allowed when errors occur. 342 // Number of remaining retries allowed when errors occur.
334 int allowed_retries_; 343 int allowed_retries_;
335 344
336 // True if operating on a per-machine installation rather than a per-user one. 345 // True if operating on a per-machine installation rather than a per-user one.
337 bool system_level_install_; 346 bool system_level_install_;
338 347
339 // The on-demand updater that is doing the work. 348 // The on-demand updater that is doing the work.
340 base::win::ScopedComPtr<IGoogleUpdate3Web> google_update_; 349 base::win::ScopedComPtr<IGoogleUpdate3Web> google_update_;
(...skipping 16 matching lines...) Expand all
357 HRESULT hresult_; 366 HRESULT hresult_;
358 int installer_exit_code_; 367 int installer_exit_code_;
359 368
360 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver); 369 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
361 }; 370 };
362 371
363 UpdateCheckDriver* UpdateCheckDriver::driver_ = nullptr; 372 UpdateCheckDriver* UpdateCheckDriver::driver_ = nullptr;
364 373
365 // static 374 // static
366 void UpdateCheckDriver::RunUpdateCheck( 375 void UpdateCheckDriver::RunUpdateCheck(
367 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 376 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
368 const std::string& locale, 377 const std::string& locale,
369 bool install_update_if_possible, 378 bool install_update_if_possible,
370 gfx::AcceleratedWidget elevation_window, 379 gfx::AcceleratedWidget elevation_window,
371 const base::WeakPtr<UpdateCheckDelegate>& delegate) { 380 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
372 // Create the driver if it doesn't exist, or add the delegate to the existing 381 // Create the driver if it doesn't exist, or add the delegate to the existing
373 // one. 382 // one.
374 if (!driver_) { 383 if (!driver_) {
375 // The driver is owned by itself, and will self-destruct when its work is 384 // The driver is owned by itself, and will self-destruct when its work is
376 // done. 385 // done.
377 driver_ = 386 driver_ =
378 new UpdateCheckDriver(task_runner, locale, install_update_if_possible, 387 new UpdateCheckDriver(task_runner, locale, install_update_if_possible,
379 elevation_window, delegate); 388 elevation_window, delegate);
380 task_runner->PostTask(FROM_HERE, 389 task_runner->PostTask(FROM_HERE,
381 base::Bind(&UpdateCheckDriver::BeginUpdateCheck, 390 base::Bind(&UpdateCheckDriver::BeginUpdateCheck,
382 base::Unretained(driver_))); 391 base::Unretained(driver_)));
383 } else { 392 } else {
384 DCHECK_EQ(driver_->task_runner_, task_runner); 393 DCHECK_EQ(driver_->task_runner_, task_runner);
385 driver_->AddDelegate(delegate); 394 driver_->AddDelegate(delegate);
386 } 395 }
387 } 396 }
388 397
389 // Runs on the caller's thread. 398 // Runs on the caller's thread.
390 UpdateCheckDriver::UpdateCheckDriver( 399 UpdateCheckDriver::UpdateCheckDriver(
391 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 400 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
392 const std::string& locale, 401 const std::string& locale,
393 bool install_update_if_possible, 402 bool install_update_if_possible,
394 gfx::AcceleratedWidget elevation_window, 403 gfx::AcceleratedWidget elevation_window,
395 const base::WeakPtr<UpdateCheckDelegate>& delegate) 404 const base::WeakPtr<UpdateCheckDelegate>& delegate)
396 : task_runner_(task_runner), 405 : task_runner_(std::move(task_runner)),
397 result_runner_(base::ThreadTaskRunnerHandle::Get()), 406 result_runner_(base::ThreadTaskRunnerHandle::Get()),
398 locale_(locale), 407 locale_(locale),
399 install_update_if_possible_(install_update_if_possible), 408 install_update_if_possible_(install_update_if_possible),
400 elevation_window_(elevation_window), 409 elevation_window_(elevation_window),
410 delegates_(1, delegate),
401 allowed_retries_(kGoogleAllowedRetries), 411 allowed_retries_(kGoogleAllowedRetries),
402 system_level_install_(false), 412 system_level_install_(false),
403 last_reported_progress_(0), 413 last_reported_progress_(0),
404 status_(UPGRADE_ERROR), 414 status_(UPGRADE_ERROR),
405 error_code_(GOOGLE_UPDATE_NO_ERROR), 415 error_code_(GOOGLE_UPDATE_NO_ERROR),
406 hresult_(S_OK), 416 hresult_(S_OK),
407 installer_exit_code_(-1) { 417 installer_exit_code_(-1) {}
408 delegates_.push_back(delegate);
409 }
410 418
411 UpdateCheckDriver::~UpdateCheckDriver() { 419 UpdateCheckDriver::~UpdateCheckDriver() {
412 DCHECK(result_runner_->BelongsToCurrentThread()); 420 DCHECK(result_runner_->BelongsToCurrentThread());
413 // If there is an error, then error_code must not be blank, and vice versa. 421 // If there is an error, then error_code must not be blank, and vice versa.
414 DCHECK_NE(status_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR); 422 DCHECK_NE(status_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR);
415 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_, 423 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_,
416 NUM_UPGRADE_STATUS); 424 NUM_UPGRADE_STATUS);
417 if (status_ == UPGRADE_ERROR) { 425 if (status_ == UPGRADE_ERROR) {
418 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_, 426 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_,
419 NUM_ERROR_CODES); 427 NUM_ERROR_CODES);
420 if (FAILED(hresult_)) 428 if (FAILED(hresult_))
421 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_); 429 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_);
422 if (installer_exit_code_ != -1) { 430 if (installer_exit_code_ != -1) {
423 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.InstallerExitCode", 431 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.InstallerExitCode",
424 installer_exit_code_); 432 installer_exit_code_);
425 } 433 }
426 } 434 }
427 435
428 // Clear the driver before calling the delegates because they might call 436 // Clear the driver before calling the delegates because they might call
429 // BeginUpdateCheck() and they must not add themselves to the current 437 // BeginUpdateCheck() and they must not add themselves to the current
430 // instance of UpdateCheckDriver, which is currently being destroyed. 438 // instance of UpdateCheckDriver, which is being destroyed.
431 driver_ = nullptr; 439 driver_ = nullptr;
432 440
433 for (const auto& delegate : delegates_) { 441 for (const auto& delegate : delegates_) {
434 if (delegate) { 442 if (delegate) {
435 if (status_ == UPGRADE_ERROR) 443 if (status_ == UPGRADE_ERROR)
436 delegate->OnError(error_code_, html_error_message_, new_version_); 444 delegate->OnError(error_code_, html_error_message_, new_version_);
437 else if (install_update_if_possible_) 445 else if (install_update_if_possible_)
438 delegate->OnUpgradeComplete(new_version_); 446 delegate->OnUpgradeComplete(new_version_);
439 else 447 else
440 delegate->OnUpdateCheckComplete(new_version_); 448 delegate->OnUpdateCheckComplete(new_version_);
441 } 449 }
442 } 450 }
443 } 451 }
444 452
453 void UpdateCheckDriver::AddDelegate(
454 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
455 DCHECK(result_runner_->BelongsToCurrentThread());
456 delegates_.push_back(delegate);
457 }
458
459 void UpdateCheckDriver::NotifyUpgradeProgress(
460 int progress,
461 const base::string16& new_version) {
462 DCHECK(result_runner_->BelongsToCurrentThread());
463
464 for (const auto& delegate : delegates_) {
465 if (delegate)
466 delegate->OnUpgradeProgress(progress, new_version);
467 }
468 }
469
445 void UpdateCheckDriver::BeginUpdateCheck() { 470 void UpdateCheckDriver::BeginUpdateCheck() {
446 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR; 471 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
447 HRESULT hresult = BeginUpdateCheckInternal(&error_code); 472 HRESULT hresult = BeginUpdateCheckInternal(&error_code);
448 if (SUCCEEDED(hresult)) { 473 if (SUCCEEDED(hresult)) {
449 // Start polling. 474 // Start polling.
450 task_runner_->PostTask(FROM_HERE, 475 task_runner_->PostTask(FROM_HERE,
451 base::Bind(&UpdateCheckDriver::PollGoogleUpdate, 476 base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
452 base::Unretained(this))); 477 base::Unretained(this)));
453 return; 478 return;
454 } 479 }
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after
776 } else if (IsIntermediateState(state, state_value, &new_version, &progress)) { 801 } else if (IsIntermediateState(state, state_value, &new_version, &progress)) {
777 bool got_new_version = new_version_.empty() && !new_version.empty(); 802 bool got_new_version = new_version_.empty() && !new_version.empty();
778 if (got_new_version) 803 if (got_new_version)
779 new_version_ = new_version; 804 new_version_ = new_version;
780 // Give the caller this status update if it differs from the last one given. 805 // Give the caller this status update if it differs from the last one given.
781 if (got_new_version || progress != last_reported_progress_) { 806 if (got_new_version || progress != last_reported_progress_) {
782 last_reported_progress_ = progress; 807 last_reported_progress_ = progress;
783 808
784 // It is safe to post this task with an unretained pointer since the task 809 // It is safe to post this task with an unretained pointer since the task
785 // is guaranteed to run before a subsequent DeleteSoon is handled. 810 // is guaranteed to run before a subsequent DeleteSoon is handled.
786 for (const auto& delegate : delegates_) { 811 result_runner_->PostTask(
787 result_runner_->PostTask( 812 FROM_HERE, base::Bind(&UpdateCheckDriver::NotifyUpgradeProgress,
788 FROM_HERE, 813 base::Unretained(this), last_reported_progress_,
789 base::Bind(&UpdateCheckDelegate::OnUpgradeProgress, delegate, 814 new_version_));
790 last_reported_progress_, new_version_));
791 }
792 } 815 }
793 816
794 // Schedule the next check. 817 // Schedule the next check.
795 task_runner_->PostDelayedTask( 818 task_runner_->PostDelayedTask(
796 FROM_HERE, base::Bind(&UpdateCheckDriver::PollGoogleUpdate, 819 FROM_HERE, base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
797 base::Unretained(this)), 820 base::Unretained(this)),
798 base::TimeDelta::FromMilliseconds(kGoogleUpdatePollIntervalMs)); 821 base::TimeDelta::FromMilliseconds(kGoogleUpdatePollIntervalMs));
799 // Early return for this non-terminal state. 822 // Early return for this non-terminal state.
800 return; 823 return;
801 } 824 }
802 825
803 // Release the reference on the COM objects before bouncing back to the 826 // Release the reference on the COM objects before bouncing back to the
804 // caller's thread. 827 // caller's thread.
805 state.Release(); 828 state.Release();
806 app_.Release(); 829 app_.Release();
807 app_bundle_.Release(); 830 app_bundle_.Release();
808 google_update_.Release(); 831 google_update_.Release();
809 832
810 result_runner_->DeleteSoon(FROM_HERE, this); 833 result_runner_->DeleteSoon(FROM_HERE, this);
811 } 834 }
812 835
813 void UpdateCheckDriver::AddDelegate(
814 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
815 delegates_.push_back(delegate);
816 }
817
818 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, 836 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
819 HRESULT hresult, 837 HRESULT hresult,
820 int installer_exit_code, 838 int installer_exit_code,
821 const base::string16& error_string) { 839 const base::string16& error_string) {
822 status_ = UPGRADE_ERROR; 840 status_ = UPGRADE_ERROR;
823 error_code_ = error_code; 841 error_code_ = error_code;
824 hresult_ = hresult; 842 hresult_ = hresult;
825 installer_exit_code_ = installer_exit_code; 843 installer_exit_code_ = installer_exit_code;
826 844
827 // Some specific result codes have dedicated messages. 845 // Some specific result codes have dedicated messages.
(...skipping 20 matching lines...) Expand all
848 IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR, error_string, html_error_msg); 866 IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR, error_string, html_error_msg);
849 } 867 }
850 } 868 }
851 869
852 } // namespace 870 } // namespace
853 871
854 872
855 // Globals --------------------------------------------------------------------- 873 // Globals ---------------------------------------------------------------------
856 874
857 void BeginUpdateCheck( 875 void BeginUpdateCheck(
858 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 876 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
859 const std::string& locale, 877 const std::string& locale,
860 bool install_update_if_possible, 878 bool install_update_if_possible,
861 gfx::AcceleratedWidget elevation_window, 879 gfx::AcceleratedWidget elevation_window,
862 const base::WeakPtr<UpdateCheckDelegate>& delegate) { 880 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
863 UpdateCheckDriver::RunUpdateCheck(task_runner, locale, 881 UpdateCheckDriver::RunUpdateCheck(std::move(task_runner), locale,
864 install_update_if_possible, 882 install_update_if_possible,
865 elevation_window, delegate); 883 elevation_window, delegate);
866 } 884 }
867 885
868 886
869 // Private API exposed for testing. -------------------------------------------- 887 // Private API exposed for testing. --------------------------------------------
870 888
871 void SetGoogleUpdateFactoryForTesting( 889 void SetGoogleUpdateFactoryForTesting(
872 const GoogleUpdate3ClassFactory& google_update_factory) { 890 const GoogleUpdate3ClassFactory& google_update_factory) {
873 if (g_google_update_factory) { 891 if (g_google_update_factory) {
874 delete g_google_update_factory; 892 delete g_google_update_factory;
875 g_google_update_factory = nullptr; 893 g_google_update_factory = nullptr;
876 } 894 }
877 if (!google_update_factory.is_null()) { 895 if (!google_update_factory.is_null()) {
878 g_google_update_factory = 896 g_google_update_factory =
879 new GoogleUpdate3ClassFactory(google_update_factory); 897 new GoogleUpdate3ClassFactory(google_update_factory);
880 } 898 }
881 } 899 }
OLDNEW
« no previous file with comments | « chrome/browser/google/google_update_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698