blob: 9ae05f124df0cd2ddbddeadcdf60f6299a1338e0 [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/app/app_install.h"
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/i18n/icu_util.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_task_runner_handle.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/control_service.h"
#include "chrome/updater/persisted_data.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/setup.h"
#include "chrome/updater/updater_version.h"
#include "components/prefs/pref_service.h"
namespace updater {
#if !defined(OS_WIN)
namespace {
class SplashScreenImpl : public SplashScreen {
public:
// Overrides for SplashScreen.
void Show() override {}
void Dismiss(base::OnceClosure callback) override {
base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(callback));
}
};
class AppInstallControllerImpl : public AppInstallController {
public:
// Override for AppInstallController.
void InstallApp(const std::string& app_id,
base::OnceCallback<void(int)> callback) override {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), 0));
}
protected:
~AppInstallControllerImpl() override = default;
};
} // namespace
scoped_refptr<App> MakeAppInstall() {
return base::MakeRefCounted<AppInstall>(
base::BindRepeating([]() -> std::unique_ptr<SplashScreen> {
return std::make_unique<SplashScreenImpl>();
}),
base::BindRepeating([]() -> scoped_refptr<AppInstallController> {
return base::MakeRefCounted<AppInstallControllerImpl>();
}));
}
#endif // !defined(OS_WIN)
AppInstall::AppInstall(SplashScreen::Maker splash_screen_maker,
AppInstallController::Maker app_install_controller_maker)
: splash_screen_maker_(std::move(splash_screen_maker)),
app_install_controller_maker_(app_install_controller_maker) {
DCHECK(splash_screen_maker_);
DCHECK(app_install_controller_maker_);
}
AppInstall::~AppInstall() = default;
void AppInstall::Initialize() {
base::i18n::InitializeICU();
// Creating |global_prefs_| requires acquiring a global lock, and this lock is
// typically owned by the RPC server. That means that if the server is
// running, the following code will block, and the install will not proceed
// until the server releases the lock.
global_prefs_ = CreateGlobalPrefs();
local_prefs_ = CreateLocalPrefs();
}
void AppInstall::FirstTaskRun() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(base::ThreadTaskRunnerHandle::IsSet());
splash_screen_ = splash_screen_maker_.Run();
splash_screen_->Show();
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::USER_BLOCKING,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce([]() { return InstallCandidate(false); }),
base::BindOnce(
[](SplashScreen* splash_screen, base::OnceCallback<void(int)> done,
int result) {
splash_screen->Dismiss(base::BindOnce(std::move(done), result));
},
splash_screen_.get(),
base::BindOnce(&AppInstall::InstallCandidateDone, this)));
}
// Updates the prefs if installing the updater is successful, then continue
// installing the application if --app-id is specified on the command line.
void AppInstall::InstallCandidateDone(int result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (result != 0) {
Shutdown(result);
return;
}
// Invoke |HandleAppId| to continue the execution flow.
MakeActive(base::BindOnce(&AppInstall::HandleAppId, this));
}
void AppInstall::HandleAppId() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This releases the prefs lock, and the RPC server can be started.
global_prefs_ = nullptr;
local_prefs_ = nullptr;
// If no app id is provided, then invoke ControlService::Run to wake
// this version of the updater, do an update check, and possibly promote
// this version as a result.
const std::string app_id =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kAppIdSwitch);
if (app_id.empty()) {
// The instance of |CreateControlService| has sequence affinity. Bind it
// in the closure to ensure it is released in this sequence.
scoped_refptr<ControlService> control_service = CreateControlService();
control_service->Run(base::BindOnce(
[](scoped_refptr<ControlService> /*control_service*/,
scoped_refptr<AppInstall> app_install) { app_install->Shutdown(0); },
control_service, base::WrapRefCounted(this)));
return;
}
app_install_controller_ = app_install_controller_maker_.Run();
app_install_controller_->InstallApp(
app_id, base::BindOnce(&AppInstall::Shutdown, this));
}
// TODO(crbug.com/1109231) - this is a temporary workaround.
void AppInstall::MakeActive(base::OnceClosure done) {
local_prefs_->SetQualified(true);
local_prefs_->GetPrefService()->CommitPendingWrite(base::BindOnce(
[](base::OnceClosure done, PrefService* pref_service) {
DCHECK(pref_service);
auto persisted_data = base::MakeRefCounted<PersistedData>(pref_service);
persisted_data->SetProductVersion(
kUpdaterAppId, base::Version(UPDATER_VERSION_STRING));
pref_service->CommitPendingWrite(std::move(done));
},
std::move(done), global_prefs_->GetPrefService()));
}
} // namespace updater