// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/updater/ipc/update_service_proxy_win.h"
#include <windows.h>
#include <wrl/client.h>
#include <wrl/implements.h>
#include <ios>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/check_op.h"
#include "base/debug/alias.h"
#include "base/debug/dump_without_crashing.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/bind_post_task.h"
#include "base/time/time.h"
#include "base/version.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_safearray.h"
#include "chrome/updater/app/server/win/updater_idl.h"
#include "chrome/updater/ipc/proxy_impl_base_win.h"
#include "chrome/updater/ipc/update_service_proxy.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/util/win_util.h"
#include "chrome/updater/win/win_constants.h"
namespace updater {
namespace {
class UpdaterObserver : public DYNAMICIIDSIMPL(IUpdaterObserver) {
public:
UpdaterObserver(
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update_callback,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback)
: state_update_callback_(state_update_callback),
callback_(std::move(callback)) {}
UpdaterObserver(const UpdaterObserver&) = delete;
UpdaterObserver& operator=(const UpdaterObserver&) = delete;
// Overrides for IUpdaterObserver. Called on a system thread by COM RPC.
IFACEMETHODIMP OnStateChange(IUpdateState* update_state) override {
CHECK(update_state);
if (!state_update_callback_) {
VLOG(2) << "Skipping posting the update state callback.";
return S_OK;
}
state_update_callback_.Run(QueryUpdateState(update_state));
return S_OK;
}
IFACEMETHODIMP OnComplete(ICompleteStatus* complete_status) override {
CHECK(complete_status);
result_ = 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.
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
Disconnect() {
VLOG(2) << __func__;
state_update_callback_.Reset();
return std::move(callback_);
}
private:
~UpdaterObserver() override {
if (callback_) {
std::move(callback_).Run(result_);
}
}
static UpdateService::UpdateState QueryUpdateState(
IUpdateState* update_state) {
CHECK(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;
std::optional<State> state = CheckedCastToEnum<State>(val_state);
if (state) {
update_service_state.state = *state;
}
VLOG_IF(2, !state) << "Fail to cast to state: " << val_state;
}
VLOG_IF(2, FAILED(hr)) << "Failed to query state: " << hr;
}
{
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;
std::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;
}
}
{
base::win::ScopedBstr installer_text;
HRESULT hr = update_state->get_installerText(installer_text.Receive());
if (SUCCEEDED(hr)) {
update_service_state.installer_text =
base::WideToUTF8(installer_text.Get());
}
}
{
base::win::ScopedBstr installer_cmd_line;
HRESULT hr =
update_state->get_installerCommandLine(installer_cmd_line.Receive());
if (SUCCEEDED(hr)) {
update_service_state.installer_cmd_line =
base::WideToUTF8(installer_cmd_line.Get());
}
}
// TODO(crbug.com/345250525) - understand why the check fails.
base::debug::Alias(&update_service_state);
if (update_service_state.state ==
UpdateService::UpdateState::State::kUnknown) {
VLOG(2) << update_service_state;
base::debug::DumpWithoutCrashing();
}
VLOG(4) << update_service_state;
return update_service_state;
}
static UpdateService::Result QueryResult(ICompleteStatus* complete_status) {
CHECK(complete_status);
LONG code = 0;
base::win::ScopedBstr message;
CHECK(SUCCEEDED(complete_status->get_statusCode(&code)));
VLOG(2) << "ICompleteStatus::OnComplete(" << code << ")";
return static_cast<UpdateService::Result>(code);
}
// Called by IUpdaterObserver::OnStateChange when update state changes occur.
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update_callback_;
// Called by IUpdaterObserver::OnComplete when the COM RPC call is done.
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback_;
UpdateService::Result result_ = UpdateService::Result::kSuccess;
};
class UpdaterCallback : public DYNAMICIIDSIMPL(IUpdaterCallback) {
public:
explicit UpdaterCallback(
base::OnceCallback<void(base::expected<LONG, RpcError>)> callback)
: callback_(std::move(callback)) {}
explicit UpdaterCallback(
base::OnceCallback<void(base::expected<int, RpcError>)> callback)
: callback_(base::BindOnce(
[](base::OnceCallback<void(base::expected<int, RpcError>)> callback,
base::expected<LONG, RpcError> result) {
std::move(callback).Run(
result.transform([](LONG x) { return static_cast<int>(x); }));
},
std::move(callback))) {}
UpdaterCallback(const UpdaterCallback&) = delete;
UpdaterCallback& operator=(const UpdaterCallback&) = delete;
// Overrides for IUpdaterCallback. Called on a system thread by COM RPC.
IFACEMETHODIMP Run(LONG status_code) override {
VLOG(2) << __func__;
status_code_ = 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(base::expected<LONG, RpcError>)> Disconnect() {
VLOG(2) << __func__;
return std::move(callback_);
}
private:
~UpdaterCallback() override {
if (callback_) {
std::move(callback_).Run(base::ok(status_code_));
}
}
base::OnceCallback<void(base::expected<LONG, RpcError>)> callback_;
LONG status_code_ = 0;
};
class UpdaterAppStatesCallback
: public DYNAMICIIDSIMPL(IUpdaterAppStatesCallback) {
public:
explicit UpdaterAppStatesCallback(
base::OnceCallback<
void(base::expected<std::vector<UpdateService::AppState>, RpcError>)>
callback)
: callback_(std::move(callback)) {}
UpdaterAppStatesCallback(const UpdaterAppStatesCallback&) = delete;
UpdaterAppStatesCallback& operator=(const UpdaterAppStatesCallback&) = delete;
// Overrides for IUpdaterAppStatesCallback. Called on a system thread by COM
// RPC.
IFACEMETHODIMP Run(VARIANT updater_app_states) override {
VLOG(2) << __func__;
if (V_VT(&updater_app_states) != (VT_ARRAY | VT_DISPATCH)) {
return E_INVALIDARG;
}
// The safearray is owned by the caller of `Run`, so ownership is released
// here after acquiring the `LockScope`.
base::win::ScopedSafearray safearray(V_ARRAY(&updater_app_states));
std::optional<base::win::ScopedSafearray::LockScope<VT_DISPATCH>>
lock_scope = safearray.CreateLockScope<VT_DISPATCH>();
safearray.Release();
if (!lock_scope.has_value() || !lock_scope->size()) {
return E_INVALIDARG;
}
for (size_t i = 0; i < lock_scope->size(); ++i) {
Microsoft::WRL::ComPtr<IDispatch> dispatch(lock_scope->at(i));
if (!dispatch) {
return E_INVALIDARG;
}
Microsoft::WRL::ComPtr<IUpdaterAppState> app_state;
const HRESULT hr =
dispatch.CopyTo(IsSystemInstall() ? __uuidof(IUpdaterAppStateSystem)
: __uuidof(IUpdaterAppStateUser),
IID_PPV_ARGS_Helper(&app_state));
if (FAILED(hr)) {
return hr;
}
app_states_.push_back(IUpdaterAppStateToAppState(app_state));
}
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(base::expected<std::vector<UpdateService::AppState>, RpcError>)>
Disconnect() {
VLOG(2) << __func__;
return std::move(callback_);
}
private:
~UpdaterAppStatesCallback() override {
if (callback_) {
std::move(callback_).Run(app_states_);
}
}
static UpdateService::AppState IUpdaterAppStateToAppState(
Microsoft::WRL::ComPtr<IUpdaterAppState> updater_app_state) {
CHECK(updater_app_state);
UpdateService::AppState app_state;
{
base::win::ScopedBstr app_id;
HRESULT hr = updater_app_state->get_appId(app_id.Receive());
if (SUCCEEDED(hr)) {
app_state.app_id = base::WideToUTF8(app_id.Get());
}
}
{
base::win::ScopedBstr version;
HRESULT hr = updater_app_state->get_version(version.Receive());
if (SUCCEEDED(hr)) {
app_state.version = base::Version(base::WideToUTF8(version.Get()));
}
}
{
base::win::ScopedBstr ap;
HRESULT hr = updater_app_state->get_ap(ap.Receive());
if (SUCCEEDED(hr)) {
app_state.ap = base::WideToUTF8(ap.Get());
}
}
{
base::win::ScopedBstr brand_code;
HRESULT hr = updater_app_state->get_brandCode(brand_code.Receive());
if (SUCCEEDED(hr)) {
app_state.brand_code = base::WideToUTF8(brand_code.Get());
}
}
{
base::win::ScopedBstr brand_path;
HRESULT hr = updater_app_state->get_brandPath(brand_path.Receive());
if (SUCCEEDED(hr)) {
app_state.brand_path = base::FilePath(brand_path.Get());
}
}
{
base::win::ScopedBstr ecp;
HRESULT hr = updater_app_state->get_ecp(ecp.Receive());
if (SUCCEEDED(hr)) {
app_state.ecp = base::FilePath(ecp.Get());
}
}
return app_state;
}
base::OnceCallback<void(
base::expected<std::vector<UpdateService::AppState>, RpcError>)>
callback_;
std::vector<UpdateService::AppState> app_states_;
};
} // namespace
class UpdateServiceProxyImplImpl
: public base::RefCountedThreadSafe<UpdateServiceProxyImplImpl>,
public ProxyImplBase<UpdateServiceProxyImplImpl,
IUpdater,
__uuidof(IUpdaterUser),
__uuidof(IUpdaterSystem)> {
public:
explicit UpdateServiceProxyImplImpl(UpdaterScope scope)
: ProxyImplBase(scope) {}
static auto GetClassGuid(UpdaterScope scope) {
return IsSystemInstall(scope) ? __uuidof(UpdaterSystemClass)
: __uuidof(UpdaterUserClass);
}
void GetVersion(
base::OnceCallback<void(base::expected<base::Version, RpcError>)>
callback) {
PostRPCTask(
base::BindOnce(&UpdateServiceProxyImplImpl::GetVersionOnTaskRunner,
this, std::move(callback)));
}
void FetchPolicies(
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
PostRPCTask(
base::BindOnce(&UpdateServiceProxyImplImpl::FetchPoliciesOnTaskRunner,
this, std::move(callback)));
}
void RegisterApp(
const RegistrationRequest& request,
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
PostRPCTask(
base::BindOnce(&UpdateServiceProxyImplImpl::RegisterAppOnTaskRunner,
this, request, std::move(callback)));
}
void GetAppStates(
base::OnceCallback<
void(base::expected<std::vector<UpdateService::AppState>, RpcError>)>
callback) {
PostRPCTask(
base::BindOnce(&UpdateServiceProxyImplImpl::GetAppStatesOnTaskRunner,
this, std::move(callback)));
}
void RunPeriodicTasks(
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
PostRPCTask(base::BindOnce(
&UpdateServiceProxyImplImpl::RunPeriodicTasksOnTaskRunner, this,
std::move(callback)));
}
void CheckForUpdate(
const std::string& app_id,
UpdateService::Priority priority,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
PostRPCTask(
base::BindOnce(&UpdateServiceProxyImplImpl::CheckForUpdateOnTaskRunner,
this, app_id, priority, policy_same_version_update,
state_update, std::move(callback)));
}
void Update(
const std::string& app_id,
const std::string& install_data_index,
UpdateService::Priority priority,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
PostRPCTask(base::BindOnce(&UpdateServiceProxyImplImpl::UpdateOnTaskRunner,
this, app_id, install_data_index, priority,
policy_same_version_update, state_update,
std::move(callback)));
}
void UpdateAll(
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
PostRPCTask(
base::BindOnce(&UpdateServiceProxyImplImpl::UpdateAllOnTaskRunner, this,
state_update, std::move(callback)));
}
void Install(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
UpdateService::Priority priority,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
PostRPCTask(base::BindOnce(&UpdateServiceProxyImplImpl::InstallOnTaskRunner,
this, registration, client_install_data,
install_data_index, priority, state_update,
std::move(callback)));
}
void CancelInstalls(const std::string& app_id) {
PostRPCTask(base::BindOnce(
&UpdateServiceProxyImplImpl::CancelInstallsOnTaskRunner, this, app_id));
}
void RunInstaller(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
PostRPCTask(
base::BindOnce(&UpdateServiceProxyImplImpl::RunInstallerOnTaskRunner,
this, app_id, installer_path, install_args, install_data,
install_settings, state_update, std::move(callback)));
}
private:
friend class base::RefCountedThreadSafe<UpdateServiceProxyImplImpl>;
virtual ~UpdateServiceProxyImplImpl() = default;
void GetVersionOnTaskRunner(
base::OnceCallback<void(base::expected<base::Version, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
base::win::ScopedBstr version;
if (HRESULT hr = get_interface()->GetVersion(version.Receive());
FAILED(hr)) {
VLOG(2) << "IUpdater::GetVersion failed: " << std::hex << hr;
std::move(callback).Run(base::unexpected(hr));
return;
}
std::move(callback).Run(base::Version(base::WideToUTF8(version.Get())));
}
void FetchPoliciesOnTaskRunner(
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
auto callback_wrapper =
MakeComObjectOrCrash<UpdaterCallback>(std::move(callback));
if (HRESULT hr = get_interface()->FetchPolicies(callback_wrapper.Get());
FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::FetchPolicies, " << std::hex << hr;
callback_wrapper->Disconnect().Run(base::unexpected(hr));
return;
}
}
void RegisterAppOnTaskRunner(
const RegistrationRequest& request,
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
std::wstring app_id_w;
std::wstring brand_code_w;
std::wstring brand_path_w;
std::wstring ap_w;
std::wstring version_w;
std::wstring existence_checker_path_w;
if (![&] {
if (!base::UTF8ToWide(request.app_id.c_str(), request.app_id.size(),
&app_id_w)) {
return false;
}
if (!base::UTF8ToWide(request.brand_code.c_str(),
request.brand_code.size(), &brand_code_w)) {
return false;
}
brand_path_w = request.brand_path.value();
if (!base::UTF8ToWide(request.ap.c_str(), request.ap.size(), &ap_w)) {
return false;
}
std::string version_str = request.version.GetString();
if (!base::UTF8ToWide(version_str.c_str(), version_str.size(),
&version_w)) {
return false;
}
existence_checker_path_w = request.existence_checker_path.value();
return true;
}()) {
std::move(callback).Run(base::ok(E_INVALIDARG));
return;
}
auto callback_wrapper =
MakeComObjectOrCrash<UpdaterCallback>(std::move(callback));
if (HRESULT hr = get_interface()->RegisterApp(
app_id_w.c_str(), brand_code_w.c_str(), brand_path_w.c_str(),
ap_w.c_str(), version_w.c_str(), existence_checker_path_w.c_str(),
callback_wrapper.Get());
FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::RegisterApp" << std::hex << hr;
callback_wrapper->Disconnect().Run(base::unexpected(hr));
return;
}
}
void GetAppStatesOnTaskRunner(
base::OnceCallback<
void(base::expected<std::vector<UpdateService::AppState>, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
auto callback_wrapper =
MakeComObjectOrCrash<UpdaterAppStatesCallback>(std::move(callback));
if (HRESULT hr = get_interface()->GetAppStates(callback_wrapper.Get());
FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::GetAppStates, " << std::hex << hr;
callback_wrapper->Disconnect().Run(base::unexpected(hr));
return;
}
}
void RunPeriodicTasksOnTaskRunner(
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
auto callback_wrapper =
MakeComObjectOrCrash<UpdaterCallback>(std::move(callback));
if (HRESULT hr = get_interface()->RunPeriodicTasks(callback_wrapper.Get());
FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::RunPeriodicTasks" << std::hex << hr;
callback_wrapper->Disconnect().Run(base::unexpected(hr));
return;
}
}
void CheckForUpdateOnTaskRunner(
const std::string& app_id,
UpdateService::Priority priority,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
std::wstring app_id_w;
if (!base::UTF8ToWide(app_id.c_str(), app_id.size(), &app_id_w)) {
std::move(callback).Run(UpdateService::Result::kServiceFailed);
return;
}
auto observer = MakeComObjectOrCrash<UpdaterObserver>(state_update,
std::move(callback));
HRESULT hr = get_interface()->CheckForUpdate(
app_id_w.c_str(), static_cast<int>(priority),
policy_same_version_update ==
UpdateService::PolicySameVersionUpdate::kAllowed,
observer.Get());
if (FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::CheckForUpdate: " << std::hex << hr;
observer->Disconnect().Run(base::unexpected(hr));
return;
}
}
void UpdateOnTaskRunner(
const std::string& app_id,
const std::string& install_data_index,
UpdateService::Priority priority,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
std::wstring app_id_w;
std::wstring install_data_index_w;
if (![&] {
if (!base::UTF8ToWide(app_id.c_str(), app_id.size(), &app_id_w)) {
return false;
}
if (!base::UTF8ToWide(install_data_index.c_str(),
install_data_index.size(),
&install_data_index_w)) {
return false;
}
return true;
}()) {
std::move(callback).Run(UpdateService::Result::kServiceFailed);
return;
}
auto observer = MakeComObjectOrCrash<UpdaterObserver>(state_update,
std::move(callback));
HRESULT hr = get_interface()->Update(
app_id_w.c_str(), install_data_index_w.c_str(),
static_cast<int>(priority),
policy_same_version_update ==
UpdateService::PolicySameVersionUpdate::kAllowed,
observer.Get());
if (FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::Update: " << std::hex << hr;
observer->Disconnect().Run(base::unexpected(hr));
return;
}
}
void UpdateAllOnTaskRunner(
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
auto observer = MakeComObjectOrCrash<UpdaterObserver>(state_update,
std::move(callback));
if (HRESULT hr = get_interface()->UpdateAll(observer.Get()); FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::UpdateAll" << std::hex << hr;
observer->Disconnect().Run(base::unexpected(hr));
return;
}
}
void InstallOnTaskRunner(
const RegistrationRequest& request,
const std::string& client_install_data,
const std::string& install_data_index,
UpdateService::Priority priority,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
std::wstring app_id_w;
std::wstring brand_code_w;
std::wstring brand_path_w;
std::wstring ap_w;
std::wstring version_w;
std::wstring existence_checker_path_w;
std::wstring client_install_data_w;
std::wstring install_data_index_w;
if (![&] {
if (!base::UTF8ToWide(request.app_id.c_str(), request.app_id.size(),
&app_id_w)) {
return false;
}
if (!base::UTF8ToWide(request.brand_code.c_str(),
request.brand_code.size(), &brand_code_w)) {
return false;
}
brand_path_w = request.brand_path.value();
if (!base::UTF8ToWide(request.ap.c_str(), request.ap.size(), &ap_w)) {
return false;
}
std::string version_str = request.version.GetString();
if (!base::UTF8ToWide(version_str.c_str(), version_str.size(),
&version_w)) {
return false;
}
existence_checker_path_w = request.existence_checker_path.value();
if (!base::UTF8ToWide(client_install_data.c_str(),
client_install_data.size(),
&client_install_data_w)) {
return false;
}
if (!base::UTF8ToWide(install_data_index.c_str(),
install_data_index.size(),
&install_data_index_w)) {
return false;
}
return true;
}()) {
std::move(callback).Run(UpdateService::Result::kServiceFailed);
return;
}
auto observer = MakeComObjectOrCrash<UpdaterObserver>(state_update,
std::move(callback));
HRESULT hr = get_interface()->Install(
app_id_w.c_str(), brand_code_w.c_str(), brand_path_w.c_str(),
ap_w.c_str(), version_w.c_str(), existence_checker_path_w.c_str(),
client_install_data_w.c_str(), install_data_index_w.c_str(),
static_cast<int>(priority), observer.Get());
if (FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::Install: " << std::hex << hr;
observer->Disconnect().Run(base::unexpected(hr));
return;
}
}
void CancelInstallsOnTaskRunner(const std::string& app_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (FAILED(ConnectToServer())) {
return;
}
if (HRESULT hr =
get_interface()->CancelInstalls(base::UTF8ToWide(app_id).c_str());
FAILED(hr)) {
VLOG(2) << "Failed to call IUpdater::CancelInstalls: " << std::hex << hr;
}
}
void RunInstallerOnTaskRunner(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
if (HRESULT hr = ConnectToServer(); FAILED(hr)) {
std::move(callback).Run(base::unexpected(hr));
return;
}
std::wstring app_id_w;
std::wstring install_args_w;
std::wstring install_data_w;
std::wstring install_settings_w;
if (![&] {
if (!base::UTF8ToWide(app_id.c_str(), app_id.size(), &app_id_w)) {
return false;
}
if (!base::UTF8ToWide(install_args.c_str(), install_args.size(),
&install_args_w)) {
return false;
}
if (!base::UTF8ToWide(install_data.c_str(), install_data.size(),
&install_data_w)) {
return false;
}
if (!base::UTF8ToWide(install_settings.c_str(),
install_settings.size(), &install_settings_w)) {
return false;
}
return true;
}()) {
std::move(callback).Run(UpdateService::Result::kServiceFailed);
return;
}
auto observer = MakeComObjectOrCrash<UpdaterObserver>(state_update,
std::move(callback));
HRESULT hr = get_interface()->RunInstaller(
app_id_w.c_str(), installer_path.value().c_str(),
install_args_w.c_str(), install_data_w.c_str(),
install_settings_w.c_str(), observer.Get());
if (SUCCEEDED(hr)) {
VLOG(2) << "IUpdater::OfflineInstall completed successfully.";
} else {
VLOG(2) << "Failed to call IUpdater::OfflineInstall: " << std::hex << hr;
observer->Disconnect().Run(base::unexpected(hr));
}
}
};
UpdateServiceProxyImpl::UpdateServiceProxyImpl(UpdaterScope updater_scope)
: impl_(base::MakeRefCounted<UpdateServiceProxyImplImpl>(updater_scope)) {}
UpdateServiceProxyImpl::~UpdateServiceProxyImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
UpdateServiceProxyImplImpl::Destroy(std::move(impl_));
}
void UpdateServiceProxyImpl::GetVersion(
base::OnceCallback<void(base::expected<base::Version, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->GetVersion(base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::FetchPolicies(
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->FetchPolicies(base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::RegisterApp(
const RegistrationRequest& request,
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->RegisterApp(request,
base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::GetAppStates(
base::OnceCallback<void(base::expected<std::vector<UpdateService::AppState>,
RpcError>)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->GetAppStates(base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::RunPeriodicTasks(
base::OnceCallback<void(base::expected<int, RpcError>)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->RunPeriodicTasks(
base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::CheckForUpdate(
const std::string& app_id,
UpdateService::Priority priority,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->CheckForUpdate(
app_id, priority, policy_same_version_update,
base::BindPostTaskToCurrentDefault(state_update),
base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::Update(
const std::string& app_id,
const std::string& install_data_index,
UpdateService::Priority priority,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->Update(app_id, install_data_index, priority,
policy_same_version_update,
base::BindPostTaskToCurrentDefault(state_update),
base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::UpdateAll(
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->UpdateAll(base::BindPostTaskToCurrentDefault(state_update),
base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::Install(
const RegistrationRequest& registration,
const std::string& client_install_data,
const std::string& install_data_index,
UpdateService::Priority priority,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->Install(registration, client_install_data, install_data_index,
priority, base::BindPostTaskToCurrentDefault(state_update),
base::BindPostTaskToCurrentDefault(std::move(callback)));
}
void UpdateServiceProxyImpl::CancelInstalls(const std::string& app_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->CancelInstalls(app_id);
}
void UpdateServiceProxyImpl::RunInstaller(
const std::string& app_id,
const base::FilePath& installer_path,
const std::string& install_args,
const std::string& install_data,
const std::string& install_settings,
base::RepeatingCallback<void(const UpdateService::UpdateState&)>
state_update,
base::OnceCallback<void(base::expected<UpdateService::Result, RpcError>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__;
impl_->RunInstaller(app_id, installer_path, install_args, install_data,
install_settings,
base::BindPostTaskToCurrentDefault(state_update),
base::BindPostTaskToCurrentDefault(std::move(callback)));
}
scoped_refptr<UpdateService> CreateUpdateServiceProxy(
UpdaterScope updater_scope,
const base::TimeDelta& /*get_version_timeout*/) {
return base::MakeRefCounted<UpdateServiceProxy>(
base::MakeRefCounted<UpdateServiceProxyImpl>(updater_scope));
}
} // namespace updater