blob: 393e8fd4fafb15f0e1709af4737a191e5c846b55 [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/browser/chromeos/crosapi/browser_loader.h"
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/chromeos/crosapi/browser_util.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/cryptohome/system_salt_getter.h"
namespace crosapi {
namespace {
constexpr char kLacrosComponentName[] = "lacros-fishfood";
// Returns whether lacros-fishfood component is already installed.
// If it is, delete the user directory, too, because it will be
// uninstalled.
bool CheckInstalledAndMaybeRemoveUserDirectory(
scoped_refptr<component_updater::CrOSComponentManager> manager) {
if (!manager->IsRegisteredMayBlock(kLacrosComponentName))
return false;
// Since we're already on a background thread, delete the user-data-dir
// associated with lacros.
// TODO(hidehiko): This approach has timing issue. Specifically, if Chrome
// shuts down during the directory remove, some partially-removed directory
// may be kept, and if the user flips the flag in the next time, that
// partially-removed directory could be used. Fix this.
base::DeletePathRecursively(browser_util::GetUserDataDir());
return true;
}
} // namespace
BrowserLoader::BrowserLoader(
scoped_refptr<component_updater::CrOSComponentManager> manager)
: component_manager_(manager) {
DCHECK(component_manager_);
}
BrowserLoader::~BrowserLoader() = default;
void BrowserLoader::Load(LoadCompletionCallback callback) {
DCHECK(browser_util::IsLacrosAllowed());
// TODO(crbug.com/1078607): Remove non-error logging from this class.
LOG(WARNING) << "Starting lacros component load.";
// If the user has specified a path for the lacros-chrome binary, use that
// rather than component manager.
base::FilePath lacros_chrome_path =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
chromeos::switches::kLacrosChromePath);
if (!lacros_chrome_path.empty()) {
OnLoadComplete(std::move(callback),
component_updater::CrOSComponentManager::Error::NONE,
lacros_chrome_path);
return;
}
component_manager_->Load(
kLacrosComponentName,
component_updater::CrOSComponentManager::MountPolicy::kMount,
component_updater::CrOSComponentManager::UpdatePolicy::kForce,
base::BindOnce(&BrowserLoader::OnLoadComplete, weak_factory_.GetWeakPtr(),
std::move(callback)));
}
void BrowserLoader::Unload() {
DCHECK(browser_util::IsLacrosAllowed());
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&CheckInstalledAndMaybeRemoveUserDirectory,
component_manager_),
base::BindOnce(&BrowserLoader::OnCheckInstalled,
weak_factory_.GetWeakPtr()));
}
void BrowserLoader::OnLoadComplete(
LoadCompletionCallback callback,
component_updater::CrOSComponentManager::Error error,
const base::FilePath& path) {
bool success =
(error == component_updater::CrOSComponentManager::Error::NONE);
if (success) {
LOG(WARNING) << "Loaded lacros image at " << path.MaybeAsASCII();
} else {
LOG(WARNING) << "Error loading lacros component image: "
<< static_cast<int>(error);
}
std::move(callback).Run(success ? path : base::FilePath());
}
void BrowserLoader::OnCheckInstalled(bool was_installed) {
if (!was_installed)
return;
// Workaround for login crash when the user un-sets the LacrosSupport flag.
// CrOSComponentManager::Unload() calls into code in MetadataTable that
// assumes that system salt is available. This isn't always true when chrome
// restarts to apply non-owner flags. It's hard to make MetadataTable async.
// Ensure salt is available before unloading. https://crbug.com/1122674
chromeos::SystemSaltGetter::Get()->GetSystemSalt(base::BindOnce(
&BrowserLoader::UnloadAfterCleanUp, weak_factory_.GetWeakPtr()));
}
void BrowserLoader::UnloadAfterCleanUp(const std::string& ignored_salt) {
CHECK(chromeos::SystemSaltGetter::Get()->GetRawSalt());
component_manager_->Unload(kLacrosComponentName);
}
} // namespace crosapi