Chromium Code Reviews| Index: chrome/browser/google/google_update_win.cc |
| diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc |
| index 61ae8ca8df282dbe2670b1cf93106bcf098acaeb..63d540566693eb67ca3f25ac2c2cee433b9638b7 100644 |
| --- a/chrome/browser/google/google_update_win.cc |
| +++ b/chrome/browser/google/google_update_win.cc |
| @@ -20,12 +20,12 @@ |
| #include "base/metrics/histogram.h" |
| #include "base/metrics/sparse_histogram.h" |
| #include "base/path_service.h" |
| +#include "base/sequenced_task_runner.h" |
| #include "base/sequenced_task_runner_helpers.h" |
| -#include "base/single_thread_task_runner.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| -#include "base/threading/thread_task_runner_handle.h" |
| +#include "base/threading/sequenced_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/version.h" |
| #include "base/win/scoped_bstr.h" |
| @@ -60,6 +60,7 @@ enum GoogleUpdateUpgradeStatus { |
| NUM_UPGRADE_STATUS |
| }; |
| +GlobalInterfaceTableClassFactory* g_git_factory = nullptr; |
|
Peter Kasting
2016/08/03 01:24:34
Nit: Prefer to avoid unusual abbreviations; |g_int
grt (UTC plus 2)
2016/08/03 05:36:30
Done.
|
| GoogleUpdate3ClassFactory* g_google_update_factory = nullptr; |
| // The time interval, in milliseconds, between polls to Google Update. This |
| @@ -122,6 +123,15 @@ void ConfigureProxyBlanket(IUnknown* interface_pointer) { |
| EOAC_DYNAMIC_CLOAKING); |
| } |
| +HRESULT CreateGlobalInterfaceTable( |
| + base::win::ScopedComPtr<IGlobalInterfaceTable>* git) { |
| + if (g_git_factory) |
| + return g_git_factory->Run(git); |
| + |
| + return git->CreateInstance(CLSID_StdGlobalInterfaceTable, nullptr, |
| + CLSCTX_INPROC_SERVER); |
| +} |
| + |
| // Creates a class factory for a COM Local Server class using either plain |
| // vanilla CoGetClassObject, or using the Elevation moniker if running on |
| // Vista+. |hwnd| must refer to a foregound window in order to get the UAC |
| @@ -203,16 +213,77 @@ HRESULT CreateGoogleUpdate3WebClass( |
| google_update->ReceiveVoid()); |
| } |
| +// GitCookie ------------------------------------------------------------------- |
| + |
| +// Manages the lifetime of an interface's cookie in the COM Global Interface |
| +// Table. |
| +template <class T> |
| +class GitCookie { |
| + public: |
| + GitCookie() = default; |
| + ~GitCookie() { Revoke(); } |
|
Peter Kasting
2016/08/03 01:24:34
Nit: You may do either, but personally I find it s
grt (UTC plus 2)
2016/08/03 05:36:30
Done.
|
| + |
| + void Initialize(base::win::ScopedComPtr<IGlobalInterfaceTable> git) { |
| + DCHECK(!git_); |
| + git_ = std::move(git); |
| + } |
| + |
| + // Registers |interface_pointer| in the process's Global Interface Table. |
| + HRESULT Register(const base::win::ScopedComPtr<T>& interface_pointer) { |
| + DCHECK(git_); |
| + DCHECK_EQ(0U, cookie_); |
| + HRESULT hresult = git_->RegisterInterfaceInGlobal( |
| + interface_pointer.get(), base::win::ScopedComPtr<T>::iid(), &cookie_); |
| + DCHECK_EQ(S_OK, hresult); |
| + return hresult; |
|
Peter Kasting
2016/08/03 01:24:34
This function and the next two should not return v
grt (UTC plus 2)
2016/08/03 05:36:30
Done.
|
| + } |
| + |
| + // Populates |interface_pointer| with the cookie's interface in the process's |
| + // Global Interface Table. |
| + HRESULT Get(base::win::ScopedComPtr<T>* interface_pointer) const { |
| + DCHECK(git_); |
| + DCHECK(interface_pointer); |
| + DCHECK_NE(0U, cookie_); |
| + HRESULT hresult = git_->GetInterfaceFromGlobal( |
| + cookie_, |
| + base::win::ScopedComPtr<T>::iid(), |
| + interface_pointer->ReceiveVoid()); |
| + DCHECK_EQ(S_OK, hresult); |
| + return hresult; |
| + } |
| + |
| + // Revokes the cookie from the Global Interface Table. This function is safe |
| + // to call when the cookie is empty. |
| + HRESULT Revoke() { |
| + HRESULT hresult = S_OK; |
| + if (cookie_) { |
| + DCHECK(git_); |
| + hresult = git_->RevokeInterfaceFromGlobal(cookie_); |
| + DCHECK_EQ(S_OK, hresult); |
| + cookie_ = 0; |
| + } |
| + return hresult; |
| + } |
| + |
| + explicit operator bool() const { return cookie_ != 0; } |
| + |
| + private: |
| + base::win::ScopedComPtr<IGlobalInterfaceTable> git_; |
| + DWORD cookie_ = 0; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(GitCookie); |
| +}; |
| + |
| // UpdateCheckDriver ----------------------------------------------------------- |
| -// A driver that is created and destroyed on the caller's thread and drives |
| +// A driver that is created and destroyed on the caller's sequence and drives |
| // Google Update on another. |
| class UpdateCheckDriver { |
| public: |
| // Runs an update check on |task_runner|, invoking methods of |delegate| on |
| - // the caller's thread to report progress and final results. |
| + // the caller's sequence to report progress and final results. |
| static void RunUpdateCheck( |
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| + scoped_refptr<base::SequencedTaskRunner> task_runner, |
| const std::string& locale, |
| bool install_update_if_possible, |
| gfx::AcceleratedWidget elevation_window, |
| @@ -221,12 +292,11 @@ class UpdateCheckDriver { |
| private: |
| friend class base::DeleteHelper<UpdateCheckDriver>; |
| - UpdateCheckDriver( |
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| - const std::string& locale, |
| - bool install_update_if_possible, |
| - gfx::AcceleratedWidget elevation_window, |
| - const base::WeakPtr<UpdateCheckDelegate>& delegate); |
| + UpdateCheckDriver(scoped_refptr<base::SequencedTaskRunner> task_runner, |
| + const std::string& locale, |
| + bool install_update_if_possible, |
| + gfx::AcceleratedWidget elevation_window, |
| + const base::WeakPtr<UpdateCheckDelegate>& delegate); |
| // Invokes a completion or error method on all delegates, as appropriate. |
| ~UpdateCheckDriver(); |
| @@ -263,7 +333,8 @@ class UpdateCheckDriver { |
| // Returns true if |current_state| and |state_value| can be obtained from the |
| // ongoing update check. Otherwise, populates |hresult| with the reason they |
| // could not be obtained. |
| - bool GetCurrentState(base::win::ScopedComPtr<ICurrentState>* current_state, |
| + bool GetCurrentState(base::win::ScopedComPtr<IAppBundleWeb>* app_bundle, |
| + base::win::ScopedComPtr<ICurrentState>* current_state, |
| CurrentState* state_value, |
| HRESULT* hresult) const; |
| @@ -278,7 +349,8 @@ class UpdateCheckDriver { |
| // chrome/installer/util/util_constants.h); otherwise, it will be -1. |
| // |error_string| will be populated with a completion message if one is |
| // provided by Google Update. |
| - bool IsErrorState(const base::win::ScopedComPtr<ICurrentState>& current_state, |
| + bool IsErrorState(const base::win::ScopedComPtr<IAppBundleWeb>& app_bundle, |
| + const base::win::ScopedComPtr<ICurrentState>& current_state, |
| CurrentState state_value, |
| GoogleUpdateErrorCode* error_code, |
| HRESULT* hresult, |
| @@ -316,15 +388,15 @@ class UpdateCheckDriver { |
| // previous notification) and another future poll will be scheduled. |
| void PollGoogleUpdate(); |
| - // The global driver instance. Accessed only on the caller's thread. |
| + // The global driver instance. Accessed only on the caller's sequence. |
| static UpdateCheckDriver* driver_; |
| // The task runner on which the update checks runs. |
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| + scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| // The caller's task runner, on which methods of the |delegates_| will be |
| // invoked. |
| - scoped_refptr<base::SingleThreadTaskRunner> result_runner_; |
| + scoped_refptr<base::SequencedTaskRunner> result_runner_; |
| // The UI locale. |
| std::string locale_; |
| @@ -336,7 +408,7 @@ class UpdateCheckDriver { |
| gfx::AcceleratedWidget elevation_window_; |
| // Contains all delegates by which feedback is conveyed. Accessed only on the |
| - // caller's thread. |
| + // caller's sequence. |
| std::vector<base::WeakPtr<UpdateCheckDelegate>> delegates_; |
| // Number of remaining retries allowed when errors occur. |
| @@ -345,14 +417,16 @@ class UpdateCheckDriver { |
| // True if operating on a per-machine installation rather than a per-user one. |
| bool system_level_install_; |
| - // The on-demand updater that is doing the work. |
| - base::win::ScopedComPtr<IGoogleUpdate3Web> google_update_; |
| + // The COM Global Interface Table for the process. |
| + base::win::ScopedComPtr<IGlobalInterfaceTable> git_; |
| - // An app bundle containing the application being updated. |
| - base::win::ScopedComPtr<IAppBundleWeb> app_bundle_; |
| + // A cookie in the Global Interface Table for the on-demand updater that is |
| + // doing the work. |
| + GitCookie<IGoogleUpdate3Web> google_update_cookie_; |
| - // The application being updated (Chrome, Chrome Binaries, or Chrome SxS). |
| - base::win::ScopedComPtr<IAppWeb> app_; |
| + // A cookie in the Global Interface Table for the app bundle containing the |
| + // application being updated. |
| + GitCookie<IAppBundleWeb> app_bundle_cookie_; |
| // The progress value reported most recently to the caller. |
| int last_reported_progress_; |
| @@ -373,7 +447,7 @@ UpdateCheckDriver* UpdateCheckDriver::driver_ = nullptr; |
| // static |
| void UpdateCheckDriver::RunUpdateCheck( |
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| + scoped_refptr<base::SequencedTaskRunner> task_runner, |
| const std::string& locale, |
| bool install_update_if_possible, |
| gfx::AcceleratedWidget elevation_window, |
| @@ -395,15 +469,15 @@ void UpdateCheckDriver::RunUpdateCheck( |
| } |
| } |
| -// Runs on the caller's thread. |
| +// Runs on the caller's sequence. |
| UpdateCheckDriver::UpdateCheckDriver( |
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| + scoped_refptr<base::SequencedTaskRunner> task_runner, |
| const std::string& locale, |
| bool install_update_if_possible, |
| gfx::AcceleratedWidget elevation_window, |
| const base::WeakPtr<UpdateCheckDelegate>& delegate) |
| : task_runner_(std::move(task_runner)), |
| - result_runner_(base::ThreadTaskRunnerHandle::Get()), |
| + result_runner_(base::SequencedTaskRunnerHandle::Get()), |
| locale_(locale), |
| install_update_if_possible_(install_update_if_possible), |
| elevation_window_(elevation_window), |
| @@ -417,7 +491,11 @@ UpdateCheckDriver::UpdateCheckDriver( |
| installer_exit_code_(-1) {} |
| UpdateCheckDriver::~UpdateCheckDriver() { |
| - DCHECK(result_runner_->BelongsToCurrentThread()); |
| + DCHECK(result_runner_->RunsTasksOnCurrentThread()); |
| + |
|
Peter Kasting
2016/08/03 01:24:34
Nit: Unnecessary blank line
grt (UTC plus 2)
2016/08/03 05:36:30
Done.
|
| + DCHECK(!google_update_cookie_); |
| + DCHECK(!app_bundle_cookie_); |
| + |
| // If there is an error, then error_code must not be blank, and vice versa. |
| DCHECK_NE(status_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR); |
| UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_, |
| @@ -452,14 +530,14 @@ UpdateCheckDriver::~UpdateCheckDriver() { |
| void UpdateCheckDriver::AddDelegate( |
| const base::WeakPtr<UpdateCheckDelegate>& delegate) { |
| - DCHECK(result_runner_->BelongsToCurrentThread()); |
| + DCHECK(result_runner_->RunsTasksOnCurrentThread()); |
| delegates_.push_back(delegate); |
| } |
| void UpdateCheckDriver::NotifyUpgradeProgress( |
| int progress, |
| const base::string16& new_version) { |
| - DCHECK(result_runner_->BelongsToCurrentThread()); |
| + DCHECK(result_runner_->RunsTasksOnCurrentThread()); |
| for (const auto& delegate : delegates_) { |
| if (delegate) |
| @@ -497,41 +575,63 @@ void UpdateCheckDriver::BeginUpdateCheck() { |
| HRESULT UpdateCheckDriver::BeginUpdateCheckInternal( |
| GoogleUpdateErrorCode* error_code) { |
| + // All errors prior to creation of the main update class are reported as: |
| + *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; |
| HRESULT hresult = S_OK; |
| - // Instantiate GoogleUpdate3Web{Machine,User}Class. |
| - if (!google_update_) { |
| + |
| + // Create/get the process's Global Interface Table. |
| + if (!git_) { |
| + // Make sure ATL is initialized in this module. |
| + ui::win::CreateATLModuleIfNeeded(); |
| + |
| + hresult = CreateGlobalInterfaceTable(&git_); |
| + if (FAILED(hresult)) |
| + return hresult; |
| + |
| + google_update_cookie_.Initialize(git_); |
| + app_bundle_cookie_.Initialize(git_); |
| + } |
| + |
| + // Create or get the GoogleUpdate3Web class. |
| + base::win::ScopedComPtr<IGoogleUpdate3Web> google_update; |
| + if (!google_update_cookie_) { |
| + // Instantiate GoogleUpdate3Web{Machine,User}Class. |
| base::FilePath chrome_exe; |
| if (!PathService::Get(base::DIR_EXE, &chrome_exe)) |
| NOTREACHED(); |
| system_level_install_ = !InstallUtil::IsPerUserInstall(chrome_exe); |
| - // Make sure ATL is initialized in this module. |
| - ui::win::CreateATLModuleIfNeeded(); |
| - |
| *error_code = CanUpdateCurrentChrome(chrome_exe, system_level_install_); |
| if (*error_code != GOOGLE_UPDATE_NO_ERROR) |
| return E_FAIL; |
| + *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; |
|
Peter Kasting
2016/08/03 01:24:34
Nit: Seems like this blank line should be above th
grt (UTC plus 2)
2016/08/03 05:36:30
I grouped it that way because I saw it as revertin
|
| hresult = CreateGoogleUpdate3WebClass(system_level_install_, |
| install_update_if_possible_, |
| - elevation_window_, &google_update_); |
| - if (FAILED(hresult)) { |
| - *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; |
| - return hresult; |
| + elevation_window_, &google_update); |
| + if (SUCCEEDED(hresult)) { |
| + ConfigureProxyBlanket(google_update.get()); |
| + |
| + hresult = google_update_cookie_.Register(google_update); |
| } |
| - ConfigureProxyBlanket(google_update_.get()); |
| + if (FAILED(hresult)) |
| + return hresult; |
| + } else { |
| + hresult = google_update_cookie_.Get(&google_update); |
| + if (FAILED(hresult)) |
| + return hresult; |
| } |
| // The class was created, so all subsequent errors are reported as: |
| *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; |
| - // Create an app bundle. |
| - if (!app_bundle_) { |
| + // Create or get the AppBundleWeb used to update Chrome. |
| + if (!app_bundle_cookie_) { |
| base::win::ScopedComPtr<IAppBundleWeb> app_bundle; |
| base::win::ScopedComPtr<IDispatch> dispatch; |
| - hresult = google_update_->createAppBundleWeb(dispatch.Receive()); |
| + hresult = google_update->createAppBundleWeb(dispatch.Receive()); |
| if (FAILED(hresult)) |
| return hresult; |
| hresult = dispatch.QueryInterface(app_bundle.Receive()); |
| @@ -558,55 +658,58 @@ HRESULT UpdateCheckDriver::BeginUpdateCheckInternal( |
| app_bundle->put_parentHWND( |
| reinterpret_cast<ULONG_PTR>(elevation_window_)); |
| } |
| - app_bundle_.swap(app_bundle); |
| - } |
| - |
| - // Get a reference to the Chrome app in the bundle. |
| - if (!app_) { |
| base::string16 app_guid = |
| installer::GetAppGuidForUpdates(system_level_install_); |
| DCHECK(!app_guid.empty()); |
| - base::win::ScopedComPtr<IDispatch> dispatch; |
| // It is common for this call to fail with APP_USING_EXTERNAL_UPDATER if |
| // an auto update is in progress. |
| - hresult = app_bundle_->createInstalledApp( |
| - base::win::ScopedBstr(app_guid.c_str())); |
| - if (FAILED(hresult)) |
| - return hresult; |
| - // Move the IAppBundleWeb reference into a local now so that failures from |
| - // this point onward result in it being released. |
| - base::win::ScopedComPtr<IAppBundleWeb> app_bundle; |
| - app_bundle.swap(app_bundle_); |
| - hresult = app_bundle->get_appWeb(0, dispatch.Receive()); |
| + hresult = |
| + app_bundle->createInstalledApp(base::win::ScopedBstr(app_guid.c_str())); |
| if (FAILED(hresult)) |
| return hresult; |
| - base::win::ScopedComPtr<IAppWeb> app; |
| - hresult = dispatch.QueryInterface(app.Receive()); |
| + hresult = app_bundle->checkForUpdate(); |
| if (FAILED(hresult)) |
| return hresult; |
| - ConfigureProxyBlanket(app.get()); |
| - hresult = app_bundle->checkForUpdate(); |
| + |
| + hresult = app_bundle_cookie_.Register(app_bundle); |
| if (FAILED(hresult)) |
| return hresult; |
| - app_bundle_.swap(app_bundle); |
| - app_.swap(app); |
| } |
| return hresult; |
| } |
| bool UpdateCheckDriver::GetCurrentState( |
| + base::win::ScopedComPtr<IAppBundleWeb>* app_bundle, |
| base::win::ScopedComPtr<ICurrentState>* current_state, |
| CurrentState* state_value, |
| HRESULT* hresult) const { |
| + // Get the bundle being checked or updated. |
| + *hresult = app_bundle_cookie_.Get(app_bundle); |
| + if (FAILED(*hresult)) |
| + return false; |
| + |
| + // Get Chrome's app from the bundle. |
| base::win::ScopedComPtr<IDispatch> dispatch; |
| - *hresult = app_->get_currentState(dispatch.Receive()); |
| + *hresult = (*app_bundle)->get_appWeb(0, dispatch.Receive()); |
| + if (FAILED(*hresult)) |
| + return false; |
| + base::win::ScopedComPtr<IAppWeb> app; |
| + *hresult = dispatch.QueryInterface(app.Receive()); |
| + if (FAILED(*hresult)) |
| + return false; |
| + dispatch.Release(); |
| + ConfigureProxyBlanket(app.get()); |
| + |
| + // Get the status of Chrome's update check or update. |
| + *hresult = app->get_currentState(dispatch.Receive()); |
| if (FAILED(*hresult)) |
| return false; |
| *hresult = dispatch.QueryInterface(current_state->Receive()); |
| if (FAILED(*hresult)) |
| return false; |
| + dispatch.Release(); |
| ConfigureProxyBlanket(current_state->get()); |
| LONG value = 0; |
| *hresult = (*current_state)->get_stateValue(&value); |
| @@ -617,6 +720,7 @@ bool UpdateCheckDriver::GetCurrentState( |
| } |
| bool UpdateCheckDriver::IsErrorState( |
| + const base::win::ScopedComPtr<IAppBundleWeb>& app_bundle, |
| const base::win::ScopedComPtr<ICurrentState>& current_state, |
| CurrentState state_value, |
| GoogleUpdateErrorCode* error_code, |
| @@ -661,7 +765,7 @@ bool UpdateCheckDriver::IsErrorState( |
| return true; |
| } |
| if (state_value == STATE_UPDATE_AVAILABLE && install_update_if_possible_) { |
| - *hresult = app_bundle_->install(); |
| + *hresult = app_bundle->install(); |
| if (FAILED(*hresult)) { |
| // Report a failure to start the install as a general error while trying |
| // to interact with Google Update. |
| @@ -774,6 +878,7 @@ bool UpdateCheckDriver::IsIntermediateState( |
| } |
| void UpdateCheckDriver::PollGoogleUpdate() { |
| + base::win::ScopedComPtr<IAppBundleWeb> app_bundle; |
| base::win::ScopedComPtr<ICurrentState> state; |
| CurrentState state_value = STATE_INIT; |
| HRESULT hresult = S_OK; |
| @@ -784,10 +889,10 @@ void UpdateCheckDriver::PollGoogleUpdate() { |
| base::string16 new_version; |
| int progress = 0; |
| - if (!GetCurrentState(&state, &state_value, &hresult)) { |
| + if (!GetCurrentState(&app_bundle, &state, &state_value, &hresult)) { |
| OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult, -1, |
| base::string16()); |
| - } else if (IsErrorState(state, state_value, &error_code, &hresult, |
| + } else if (IsErrorState(app_bundle, state, state_value, &error_code, &hresult, |
| &installer_exit_code, &error_string)) { |
| OnUpgradeError(error_code, hresult, installer_exit_code, error_string); |
| } else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) { |
| @@ -824,11 +929,11 @@ void UpdateCheckDriver::PollGoogleUpdate() { |
| } |
| // Release the reference on the COM objects before bouncing back to the |
| - // caller's thread. |
| + // caller's sequence. |
| state.Release(); |
| - app_.Release(); |
| - app_bundle_.Release(); |
| - google_update_.Release(); |
| + app_bundle.Release(); |
| + app_bundle_cookie_.Revoke(); |
| + google_update_cookie_.Revoke(); |
| result_runner_->DeleteSoon(FROM_HERE, this); |
| } |
| @@ -865,6 +970,9 @@ void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, |
| html_error_message_ = l10n_util::GetStringFUTF16( |
| IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR, error_string, html_error_msg); |
| } |
| + |
| + app_bundle_cookie_.Revoke(); |
| + google_update_cookie_.Revoke(); |
| } |
| } // namespace |
| @@ -872,12 +980,11 @@ void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, |
| // Globals --------------------------------------------------------------------- |
| -void BeginUpdateCheck( |
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| - const std::string& locale, |
| - bool install_update_if_possible, |
| - gfx::AcceleratedWidget elevation_window, |
| - const base::WeakPtr<UpdateCheckDelegate>& delegate) { |
| +void BeginUpdateCheck(scoped_refptr<base::SequencedTaskRunner> task_runner, |
| + const std::string& locale, |
| + bool install_update_if_possible, |
| + gfx::AcceleratedWidget elevation_window, |
| + const base::WeakPtr<UpdateCheckDelegate>& delegate) { |
| UpdateCheckDriver::RunUpdateCheck(std::move(task_runner), locale, |
| install_update_if_possible, |
| elevation_window, delegate); |
| @@ -886,8 +993,16 @@ void BeginUpdateCheck( |
| // Private API exposed for testing. -------------------------------------------- |
| -void SetGoogleUpdateFactoryForTesting( |
| +void SetUpdateCheckFactoriesForTesting( |
| + const GlobalInterfaceTableClassFactory& git_factory, |
| const GoogleUpdate3ClassFactory& google_update_factory) { |
| + if (g_git_factory) { |
| + delete g_git_factory; |
| + g_git_factory = nullptr; |
| + } |
| + if (!git_factory.is_null()) |
| + g_git_factory = new GlobalInterfaceTableClassFactory(git_factory); |
| + |
| if (g_google_update_factory) { |
| delete g_google_update_factory; |
| g_google_update_factory = nullptr; |