blob: 06237a7f71dfc186eb81283d47ac2a035debc621 [file] [log] [blame]
// Copyright 2020 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/updater/win/update_service_proxy.h"
#include <windows.h>
#include <wrl/client.h>
#include <wrl/implements.h>
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/bind_post_task.h"
#include "base/callback.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_checker.h"
#include "base/version.h"
#include "base/win/scoped_bstr.h"
#include "chrome/updater/app/server/win/updater_idl.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/util.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace updater {
namespace {
using IUpdateStatePtr = ::Microsoft::WRL::ComPtr<IUpdateState>;
using ICompleteStatusPtr = ::Microsoft::WRL::ComPtr<ICompleteStatus>;
static constexpr base::TaskTraits kComClientTraits = {
base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
// Creates an instance of IUpdater in the COM STA apartment.
HRESULT CreateUpdater(UpdaterScope scope,
Microsoft::WRL::ComPtr<IUpdater>& updater) {
Microsoft::WRL::ComPtr<IUnknown> server;
HRESULT hr = ::CoCreateInstance(
scope == UpdaterScope::kSystem ? __uuidof(UpdaterSystemClass)
: __uuidof(UpdaterUserClass),
nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&server));
if (FAILED(hr)) {
DVLOG(2) << "Failed to instantiate the update server: " << std::hex << hr;
return hr;
}
Microsoft::WRL::ComPtr<IUpdater> updater_local;
hr = server.As(&updater_local);
if (FAILED(hr)) {
DVLOG(2) << "Failed to query the updater interface: " << std::hex << hr;
return hr;
}
updater = updater_local;
return S_OK;
}
// This class implements the IUpdaterObserver interface and exposes it as a COM
// object. The class has thread-affinity for the STA thread. However, its
// functions are invoked directly by COM RPC, and they are not sequenced through
// the thread task runner. This means that sequence checkers can't be used in
// this class.
class UpdaterObserver
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
IUpdaterObserver> {
public:
UpdaterObserver(Microsoft::WRL::ComPtr<IUpdater> updater,
UpdateService::StateChangeCallback state_update_callback,
UpdateService::Callback callback);
UpdaterObserver(const UpdaterObserver&) = delete;
UpdaterObserver& operator=(const UpdaterObserver&) = delete;
// Overrides for IUpdaterObserver. These functions are called on the STA
// thread directly by the COM RPC runtime.
//
// The implementation of this function queries the data in the `update_state`
// object, then post a callback through the `com_task_runner_` to sequence
// the execution of the COM code and the rest of the code in this module.
// The `update_state` object is queried before returning the execution
// flow back to the RPC channel, otherwise the RPC server keeps sending
// state change notifications which queue up in the `com_task_runner_`.
IFACEMETHODIMP OnStateChange(IUpdateState* update_state) override {
DCHECK(update_state);
com_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&UpdaterObserver::OnStateChangeOnSTA,
base::WrapRefCounted(this),
QueryUpdateState(update_state)));
return S_OK;
}
// See the comment above.
IFACEMETHODIMP OnComplete(ICompleteStatus* complete_status) override {
DCHECK(complete_status);
com_task_runner_->PostTask(FROM_HERE,
base::BindOnce(&UpdaterObserver::OnCompleteOnSTA,
base::WrapRefCounted(this),
QueryResult(complete_status)));
return S_OK;
}
// Disconnects this observer from its subject and ensures the callbacks are
// not posted after this function is called. Returns the completion callback
// so that the owner of this object can take back the callback ownership.
UpdateService::Callback Disconnect();
private:
~UpdaterObserver() override;
// Called in sequence on the `com_task_runner_`.
void OnStateChangeOnSTA(
const UpdateService::UpdateState& update_service_state);
void OnCompleteOnSTA(const UpdateService::Result& result);
UpdateService::UpdateState QueryUpdateState(IUpdateState* update_state);
UpdateService::Result QueryResult(ICompleteStatus* complete_status);
// Bound to the STA thread.
THREAD_CHECKER(thread_checker_);
// Bound to the STA thread.
scoped_refptr<base::SequencedTaskRunner> com_task_runner_;
// Keeps a reference of the updater object alive, while this object is
// owned by the COM RPC runtime.
Microsoft::WRL::ComPtr<IUpdater> updater_;
// Called by IUpdaterObserver::OnStateChange when update state change occur.
UpdateService::StateChangeCallback state_update_callback_;
// Called by IUpdaterObserver::OnComplete when the COM RPC call is done.
UpdateService::Callback callback_;
};
// This class implements the IUpdaterRegisterAppCallback interface and exposes
// it as a COM object. The class has thread-affinity for the STA thread.
// However, its functions are invoked directly by COM RPC, and they are not
// sequenced through the thread task runner. This means that sequence checkers
// can't be used in this class.
class UpdaterRegisterAppCallback
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
IUpdaterRegisterAppCallback> {
public:
UpdaterRegisterAppCallback(Microsoft::WRL::ComPtr<IUpdater> updater,
UpdateService::RegisterAppCallback callback);
UpdaterRegisterAppCallback(const UpdaterRegisterAppCallback&) = delete;
UpdaterRegisterAppCallback& operator=(const UpdaterRegisterAppCallback&) =
delete;
// Overrides for IUpdaterRegisterAppCallback. These functions are called on
// the STA thread directly by the COM RPC runtime.
IFACEMETHODIMP Run(LONG status_code) override {
com_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&UpdaterRegisterAppCallback::OnRunOnSTA,
base::WrapRefCounted(this), status_code));
return S_OK;
}
// Disconnects this observer from its subject and ensures the callbacks are
// not posted after this function is called. Returns the completion callback
// so that the owner of this object can take back the callback ownership.
UpdateService::RegisterAppCallback Disconnect();
private:
~UpdaterRegisterAppCallback() override;
// Called in sequence on the `com_task_runner_`.
void OnRunOnSTA(LONG status_code);
// Bound to the STA thread.
THREAD_CHECKER(thread_checker_);
// Bound to the STA thread.
scoped_refptr<base::SequencedTaskRunner> com_task_runner_;
// Keeps a reference of the updater object alive, while this object is
// owned by the COM RPC runtime.
Microsoft::WRL::ComPtr<IUpdater> updater_;
// Called by IUpdaterObserver::OnComplete when the COM RPC call is done.
UpdateService::RegisterAppCallback callback_;
};
// This class implements the IUpdaterCallback interface and exposes it as a COM
// object. The class has thread-affinity for the STA thread. However, its
// functions are invoked directly by COM RPC, and they are not sequenced through
// the thread task runner. This means that sequence checkers can't be used in
// this class.
class UpdaterCallback
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
IUpdaterCallback> {
public:
UpdaterCallback(Microsoft::WRL::ComPtr<IUpdater> updater,
base::OnceCallback<void(LONG)> callback);
UpdaterCallback(const UpdaterCallback&) = delete;
UpdaterCallback& operator=(const UpdaterCallback&) = delete;
// Overrides for IUpdaterCallback. These functions are called on
// the STA thread directly by the COM RPC runtime.
IFACEMETHODIMP Run(LONG status_code) override {
com_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&UpdaterCallback::OnRunOnSTA,
base::WrapRefCounted(this), status_code));
return S_OK;
}
// Disconnects this observer from its subject and ensures the callbacks are
// not posted after this function is called. Returns the completion callback
// so that the owner of this object can take back the callback ownership.
base::OnceCallback<void(LONG)> Disconnect();
private:
~UpdaterCallback() override;
// Called in sequence on the `com_task_runner_`.
void OnRunOnSTA(LONG status_code);
// Bound to the STA thread.
THREAD_CHECKER(thread_checker_);
// Bound to the STA thread.
scoped_refptr<base::SequencedTaskRunner> com_task_runner_;
// Keeps a reference of the updater object alive, while this object is
// owned by the COM RPC runtime.
Microsoft::WRL::ComPtr<IUpdater> updater_;
base::OnceCallback<void(LONG)> callback_;
};
} // namespace
UpdaterObserver::UpdaterObserver(
Microsoft::WRL::ComPtr<IUpdater> updater,
UpdateService::StateChangeCallback state_update_callback,
UpdateService::Callback callback)
: com_task_runner_(base::SequencedTaskRunnerHandle::Get()),
updater_(updater),
state_update_callback_(state_update_callback),
callback_(std::move(callback)) {}
UpdaterObserver::~UpdaterObserver() = default;
UpdateService::Callback UpdaterObserver::Disconnect() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DVLOG(2) << __func__;
updater_ = nullptr;
state_update_callback_.Reset();
return std::move(callback_);
}
UpdateService::UpdateState UpdaterObserver::QueryUpdateState(
IUpdateState* update_state) {
DCHECK(update_state);
UpdateService::UpdateState update_service_state;
{
LONG val_state = 0;
HRESULT hr = update_state->get_state(&val_state);
if (SUCCEEDED(hr)) {
using State = UpdateService::UpdateState::State;
absl::optional<State> state = CheckedCastToEnum<State>(val_state);
if (state)
update_service_state.state = *state;
}
}
{
base::win::ScopedBstr app_id;
HRESULT hr = update_state->get_appId(app_id.Receive());
if (SUCCEEDED(hr))
update_service_state.app_id = base::WideToUTF8(app_id.Get());
}
{
base::win::ScopedBstr next_version;
HRESULT hr = update_state->get_nextVersion(next_version.Receive());
if (SUCCEEDED(hr)) {
update_service_state.next_version =
base::Version(base::WideToUTF8(next_version.Get()));
}
}
{
LONGLONG downloaded_bytes = -1;
HRESULT hr = update_state->get_downloadedBytes(&downloaded_bytes);
if (SUCCEEDED(hr))
update_service_state.downloaded_bytes = downloaded_bytes;
}
{
LONGLONG total_bytes = -1;
HRESULT hr = update_state->get_totalBytes(&total_bytes);
if (SUCCEEDED(hr))
update_service_state.total_bytes = total_bytes;
}
{
LONG install_progress = -1;
HRESULT hr = update_state->get_installProgress(&install_progress);
if (SUCCEEDED(hr))
update_service_state.install_progress = install_progress;
}
{
LONG val_error_category = 0;
HRESULT hr = update_state->get_errorCategory(&val_error_category);
if (SUCCEEDED(hr)) {
using ErrorCategory = UpdateService::ErrorCategory;
absl::optional<ErrorCategory> error_category =
CheckedCastToEnum<ErrorCategory>(val_error_category);
if (error_category)
update_service_state.error_category = *error_category;
}
}
{
LONG error_code = -1;
HRESULT hr = update_state->get_errorCode(&error_code);
if (SUCCEEDED(hr))
update_service_state.error_code = error_code;
}
{
LONG extra_code1 = -1;
HRESULT hr = update_state->get_extraCode1(&extra_code1);
if (SUCCEEDED(hr))
update_service_state.extra_code1 = extra_code1;
}
DVLOG(4) << update_service_state;
return update_service_state;
}
UpdateService::Result UpdaterObserver::QueryResult(
ICompleteStatus* complete_status) {
DCHECK(complete_status);
LONG code = 0;
base::win::ScopedBstr message;
CHECK(SUCCEEDED(complete_status->get_statusCode(&code)));
DVLOG(2) << "ICompleteStatus::OnComplete(" << code << ")";
return static_cast<UpdateService::Result>(code);
}
void UpdaterObserver::OnStateChangeOnSTA(
const UpdateService::UpdateState& update_service_state) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DVLOG(4) << __func__;
if (!state_update_callback_) {
DVLOG(4) << "Skipping posting the update state callback.";
return;
}
com_task_runner_->PostTask(
FROM_HERE, base::BindOnce(state_update_callback_, update_service_state));
}
void UpdaterObserver::OnCompleteOnSTA(const UpdateService::Result& result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
updater_ = nullptr;
if (!callback_) {
DVLOG(2) << "Skipping posting the completion callback.";
return;
}
com_task_runner_->PostTask(FROM_HERE,
base::BindOnce(std::move(callback_), result));
}
UpdaterRegisterAppCallback::UpdaterRegisterAppCallback(
Microsoft::WRL::ComPtr<IUpdater> updater,
UpdateService::RegisterAppCallback callback)
: com_task_runner_(base::SequencedTaskRunnerHandle::Get()),
updater_(updater),
callback_(std::move(callback)) {}
UpdaterRegisterAppCallback::~UpdaterRegisterAppCallback() = default;
UpdateService::RegisterAppCallback UpdaterRegisterAppCallback::Disconnect() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DVLOG(2) << __func__;
updater_ = nullptr;
return std::move(callback_);
}
void UpdaterRegisterAppCallback::OnRunOnSTA(LONG status_code) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DVLOG(4) << __func__;
if (!callback_) {
DVLOG(4) << "Skipping posting the register app callback.";
return;
}
com_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback_), RegistrationResponse(status_code)));
}
UpdaterCallback::UpdaterCallback(Microsoft::WRL::ComPtr<IUpdater> updater,
base::OnceCallback<void(LONG)> callback)
: com_task_runner_(base::SequencedTaskRunnerHandle::Get()),
updater_(updater),
callback_(std::move(callback)) {}
UpdaterCallback::~UpdaterCallback() = default;
base::OnceCallback<void(LONG)> UpdaterCallback::Disconnect() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DVLOG(2) << __func__;
updater_ = nullptr;
return std::move(callback_);
}
void UpdaterCallback::OnRunOnSTA(LONG status_code) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DVLOG(4) << __func__;
if (!callback_) {
DVLOG(4) << "Skipping posting the callback.";
return;
}
com_task_runner_->PostTask(FROM_HERE,
base::BindOnce(std::move(callback_), status_code));
}
UpdateServiceProxy::UpdateServiceProxy(UpdaterScope updater_scope)
: scope_(updater_scope),
main_task_runner_(base::SequencedTaskRunnerHandle::Get()),
com_task_runner_(
base::ThreadPool::CreateCOMSTATaskRunner(kComClientTraits)) {}
UpdateServiceProxy::~UpdateServiceProxy() = default;
void UpdateServiceProxy::GetVersion(
base::OnceCallback<void(const base::Version&)> callback) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
com_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&UpdateServiceProxy::GetVersionOnSTA, this,
base::BindOnce(
[](scoped_refptr<base::SequencedTaskRunner> taskrunner,
base::OnceCallback<void(const base::Version&)> callback,
const base::Version& version) {
taskrunner->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), version));
},
base::SequencedTaskRunnerHandle::Get(), std::move(callback))));
}
void UpdateServiceProxy::RegisterApp(const RegistrationRequest& request,
RegisterAppCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Reposts the call to the COM task runner. Adapts `callback` so that
// the callback runs on the main sequence.
com_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&UpdateServiceProxy::RegisterAppOnSTA, this, request,
base::BindOnce(
[](scoped_refptr<base::SequencedTaskRunner> taskrunner,
RegisterAppCallback callback,
const RegistrationResponse& response) {
taskrunner->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), response));
},
base::SequencedTaskRunnerHandle::Get(), std::move(callback))));
}
void UpdateServiceProxy::RunPeriodicTasks(base::OnceClosure callback) {
com_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&UpdateServiceProxy::RunPeriodicTasksOnSTA, this,
base::BindPostTask(base::SequencedTaskRunnerHandle::Get(),
std::move(callback))));
}
void UpdateServiceProxy::UpdateAll(StateChangeCallback state_update,
Callback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Reposts the call to the COM task runner. Adapts `callback` so that
// the callback runs on the main sequence.
com_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&UpdateServiceProxy::UpdateAllOnSTA, this, state_update,
base::BindOnce(
[](scoped_refptr<base::SequencedTaskRunner> taskrunner,
Callback callback, Result result) {
taskrunner->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), result));
},
base::SequencedTaskRunnerHandle::Get(), std::move(callback))));
}
void UpdateServiceProxy::Update(const std::string& app_id,
UpdateService::Priority /*priority*/,
StateChangeCallback state_update,
Callback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Reposts the call to the COM task runner. Adapts `callback` so that
// the callback runs on the main sequence.
com_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&UpdateServiceProxy::UpdateOnSTA, this, app_id,
base::BindRepeating(
[](scoped_refptr<base::SequencedTaskRunner> taskrunner,
StateChangeCallback state_update, UpdateState update_state) {
taskrunner->PostTask(
FROM_HERE, base::BindRepeating(state_update, update_state));
},
base::SequencedTaskRunnerHandle::Get(), state_update),
base::BindOnce(
[](scoped_refptr<base::SequencedTaskRunner> taskrunner,
Callback callback, Result result) {
taskrunner->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), result));
},
base::SequencedTaskRunnerHandle::Get(), std::move(callback))));
}
void UpdateServiceProxy::Uninitialize() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void UpdateServiceProxy::GetVersionOnSTA(
base::OnceCallback<void(const base::Version&)> callback) const {
DCHECK(com_task_runner_->BelongsToCurrentThread());
Microsoft::WRL::ComPtr<IUpdater> updater;
HRESULT hr = CreateUpdater(scope_, updater);
if (FAILED(hr)) {
DVLOG(2) << "Failed to create the updater interface: " << std::hex << hr;
std::move(callback).Run(base::Version());
return;
}
base::win::ScopedBstr version;
hr = updater->GetVersion(version.Receive());
if (FAILED(hr)) {
DVLOG(2) << "IUpdater::GetVersion failed: " << std::hex << hr;
std::move(callback).Run(base::Version());
return;
}
std::move(callback).Run(base::Version(base::WideToUTF8(version.Get())));
}
void UpdateServiceProxy::RegisterAppOnSTA(
const RegistrationRequest& request,
base::OnceCallback<void(const RegistrationResponse&)> callback) {
DCHECK(com_task_runner_->BelongsToCurrentThread());
Microsoft::WRL::ComPtr<IUpdater> updater;
HRESULT hr = CreateUpdater(scope_, updater);
if (FAILED(hr)) {
DVLOG(2) << "Failed to create the updater interface: " << std::hex << hr;
std::move(callback).Run(RegistrationResponse(hr));
return;
}
std::wstring app_id;
std::wstring brand_code;
std::wstring tag;
std::wstring version;
std::wstring existence_checker_path;
if (![&]() {
if (!base::UTF8ToWide(request.app_id.c_str(), request.app_id.size(),
&app_id)) {
return false;
}
if (!base::UTF8ToWide(request.brand_code.c_str(),
request.brand_code.size(), &brand_code)) {
return false;
}
if (!base::UTF8ToWide(request.tag.c_str(), request.tag.size(), &tag)) {
return false;
}
std::string version_str = request.version.GetString();
if (!base::UTF8ToWide(version_str.c_str(), version_str.size(),
&version)) {
return false;
}
existence_checker_path = request.existence_checker_path.value();
return true;
}()) {
std::move(callback).Run(RegistrationResponse(-1));
return;
}
auto callback_wrapper = Microsoft::WRL::Make<UpdaterRegisterAppCallback>(
updater, std::move(callback));
hr = updater->RegisterApp(app_id.c_str(), brand_code.c_str(), tag.c_str(),
version.c_str(), existence_checker_path.c_str(),
callback_wrapper.Get());
if (FAILED(hr)) {
DVLOG(2) << "Failed to call IUpdater::RegisterApp" << std::hex << hr;
callback_wrapper->Disconnect().Run(RegistrationResponse(hr));
return;
}
}
void UpdateServiceProxy::RunPeriodicTasksOnSTA(base::OnceClosure callback) {
DCHECK(com_task_runner_->BelongsToCurrentThread());
Microsoft::WRL::ComPtr<IUpdater> updater;
HRESULT hr = CreateUpdater(scope_, updater);
if (FAILED(hr)) {
DVLOG(2) << "Failed to create the updater interface: " << std::hex << hr;
std::move(callback).Run();
return;
}
auto callback_wrapper = Microsoft::WRL::Make<UpdaterCallback>(
updater, base::BindOnce([](base::OnceClosure callback,
LONG unused) { std::move(callback).Run(); },
std::move(callback)));
hr = updater->RunPeriodicTasks(callback_wrapper.Get());
if (FAILED(hr)) {
DVLOG(2) << "Failed to call IUpdater::RunPeriodicTasks" << std::hex << hr;
callback_wrapper->Disconnect().Run(hr);
return;
}
}
void UpdateServiceProxy::UpdateAllOnSTA(StateChangeCallback state_update,
Callback callback) {
DCHECK(com_task_runner_->BelongsToCurrentThread());
Microsoft::WRL::ComPtr<IUpdater> updater;
HRESULT hr = CreateUpdater(scope_, updater);
if (FAILED(hr)) {
DVLOG(2) << "Failed to create the updater interface: " << std::hex << hr;
std::move(callback).Run(Result::kServiceFailed);
return;
}
// The COM RPC takes ownership of the `observer` and owns a reference to
// the updater object as well. As long as the `observer` retains this
// reference to the updater object, then the object is going to stay alive.
// The `observer` can drop its reference to the updater object after
// handling the last server callback, then the object model is torn down,
// and finally, the execution flow returns back into the App object once the
// completion callback is posted.
auto observer = Microsoft::WRL::Make<UpdaterObserver>(updater, state_update,
std::move(callback));
hr = updater->UpdateAll(observer.Get());
if (FAILED(hr)) {
DVLOG(2) << "Failed to call IUpdater::UpdateAll" << std::hex << hr;
// Since the RPC call returned an error, it can't be determined what the
// state of the update server is. The observer may or may not post any
// callback. Disconnecting the observer resolves this ambiguity and
// transfers the ownership of the callback back to the owner of the
// observer.
observer->Disconnect().Run(Result::kServiceFailed);
return;
}
}
void UpdateServiceProxy::UpdateOnSTA(const std::string& app_id,
StateChangeCallback state_update,
Callback callback) {
DCHECK(com_task_runner_->BelongsToCurrentThread());
Microsoft::WRL::ComPtr<IUpdater> updater;
HRESULT hr = CreateUpdater(scope_, updater);
if (FAILED(hr)) {
DVLOG(2) << "Failed to create the updater interface: " << std::hex << hr;
std::move(callback).Run(Result::kServiceFailed);
return;
}
auto observer = Microsoft::WRL::Make<UpdaterObserver>(updater, state_update,
std::move(callback));
hr = updater->Update(base::UTF8ToWide(app_id).c_str(), observer.Get());
if (FAILED(hr)) {
DVLOG(2) << "Failed to call IUpdater::UpdateAll: " << std::hex << hr;
// See the comment in the implementation of `UpdateAllOnSTA`.
observer->Disconnect().Run(Result::kServiceFailed);
return;
}
}
} // namespace updater