blob: 47c3e34c19553349be30a1f8fd756b547362cb95 [file] [log] [blame]
// Copyright 2023 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/browser/web_applications/commands/install_from_manifest_command.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "chrome/browser/web_applications/locks/shared_web_contents_lock.h"
#include "chrome/browser/web_applications/locks/shared_web_contents_with_app_lock.h"
#include "chrome/browser/web_applications/locks/web_app_lock_manager.h"
#include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
#include "chrome/browser/web_applications/web_app_command_manager.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_id.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "chrome/browser/web_applications/web_app_install_params.h"
#include "chrome/browser/web_applications/web_app_install_utils.h"
#include "components/webapps/browser/install_result_code.h"
#include "components/webapps/browser/installable/installable_metrics.h"
#include "content/public/browser/web_contents.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/common/manifest/manifest_util.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
#include "third_party/blink/public/mojom/manifest/manifest_manager.mojom.h"
#include "url/url_constants.h"
namespace web_app {
InstallFromManifestCommand::InstallFromManifestCommand(
webapps::WebappInstallSource install_source,
GURL document_url,
GURL manifest_url,
std::string manifest_contents,
AppId expected_id,
OnceInstallCallback callback)
: WebAppCommandTemplate<SharedWebContentsLock>(
"InstallFromManifestCommand"),
install_source_(install_source),
document_url_(std::move(document_url)),
manifest_url_(std::move(manifest_url)),
manifest_contents_(std::move(manifest_contents)),
expected_id_(std::move(expected_id)),
install_callback_(std::move(callback)),
web_contents_lock_description_(
std::make_unique<SharedWebContentsLockDescription>()) {}
InstallFromManifestCommand::~InstallFromManifestCommand() = default;
LockDescription& InstallFromManifestCommand::lock_description() const {
DCHECK(web_contents_lock_description_ || app_lock_description_);
if (app_lock_description_) {
return *app_lock_description_;
}
return *web_contents_lock_description_;
}
void InstallFromManifestCommand::StartWithLock(
std::unique_ptr<SharedWebContentsLock> lock) {
web_contents_lock_ = std::move(lock);
// The shared web contents must have been reset to about:blank before command
// execution.
DCHECK_EQ(web_contents_lock_->shared_web_contents().GetURL(),
GURL(url::kAboutBlankURL));
web_contents_lock_->shared_web_contents()
.GetPrimaryMainFrame()
->GetRemoteInterfaces()
->GetInterface(manifest_manager_.BindNewPipeAndPassReceiver());
manifest_manager_.set_disconnect_handler(
base::BindOnce(&InstallFromManifestCommand::Abort,
weak_ptr_factory_.GetWeakPtr(), CommandResult::kFailure,
webapps::InstallResultCode::kWebContentsDestroyed));
manifest_manager_->ParseManifestFromString(
document_url_, manifest_url_, manifest_contents_,
base::BindOnce(&InstallFromManifestCommand::OnManifestParsed,
weak_ptr_factory_.GetWeakPtr()));
}
base::Value InstallFromManifestCommand::ToDebugValue() const {
base::Value::Dict debug_value;
debug_value.Set("document_url", document_url_.spec());
debug_value.Set("manifest_url", manifest_url_.spec());
debug_value.Set("manifest_contents", manifest_contents_);
debug_value.Set("manifest_parsed", manifest_parsed_);
return base::Value(std::move(debug_value));
}
void InstallFromManifestCommand::OnShutdown() {
Abort(CommandResult::kShutdown,
webapps::InstallResultCode::kCancelledOnWebAppProviderShuttingDown);
}
void InstallFromManifestCommand::OnSyncSourceRemoved() {}
void InstallFromManifestCommand::OnManifestParsed(
blink::mojom::ManifestPtr manifest) {
// Note that most errors during parsing (e.g. errors to do with parsing a
// particular field) are silently ignored. As long as the manifest is valid
// JSON and contains a valid start_url, installation will proceed.
if (blink::IsEmptyManifest(manifest) || !manifest->start_url.is_valid()) {
Abort(CommandResult::kFailure,
webapps::InstallResultCode::kNotValidManifestForWebApp);
return;
}
manifest_parsed_ = true;
web_app_info_ = std::make_unique<WebAppInstallInfo>();
web_app_info_->user_display_mode = mojom::UserDisplayMode::kStandalone;
UpdateWebAppInfoFromManifest(*manifest, manifest_url_, web_app_info_.get());
// Generates a fallback icon for the app.
// TODO(crbug.com/1402583): Download and use real icons.
PopulateProductIcons(web_app_info_.get(), nullptr);
AppId app_id =
GenerateAppId(web_app_info_->manifest_id, web_app_info_->start_url);
if (app_id != expected_id_) {
Abort(CommandResult::kFailure,
webapps::InstallResultCode::kExpectedAppIdCheckFailed);
return;
}
app_lock_description_ =
command_manager()->lock_manager().UpgradeAndAcquireLock(
std::move(web_contents_lock_), {app_id},
base::BindOnce(&InstallFromManifestCommand::OnAppLockAcquired,
weak_ptr_factory_.GetWeakPtr()));
}
void InstallFromManifestCommand::OnAppLockAcquired(
std::unique_ptr<SharedWebContentsWithAppLock> app_lock) {
app_lock_ = std::move(app_lock);
WebAppInstallFinalizer::FinalizeOptions finalize_options(install_source_);
finalize_options.add_to_quick_launch_bar = false;
finalize_options.overwrite_existing_manifest_fields = false;
app_lock_->install_finalizer().FinalizeInstall(
*web_app_info_, finalize_options,
base::BindOnce(&InstallFromManifestCommand::OnInstallFinalized,
weak_ptr_factory_.GetWeakPtr()));
}
void InstallFromManifestCommand::OnInstallFinalized(
const AppId& app_id,
webapps::InstallResultCode code,
OsHooksErrors os_hooks_errors) {
SignalCompletionAndSelfDestruct(
webapps::IsSuccess(code) ? CommandResult::kSuccess
: CommandResult::kFailure,
base::BindOnce(std::move(install_callback_), app_id, code));
}
void InstallFromManifestCommand::Abort(CommandResult result,
webapps::InstallResultCode code) {
SignalCompletionAndSelfDestruct(
result, base::BindOnce(std::move(install_callback_), AppId(), code));
}
} // namespace web_app