chromium/chrome/browser/web_applications/web_app_install_finalizer.cc

// Copyright 2018 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/web_app_install_finalizer.h"

#include <map>
#include <utility>

#include "base/barrier_callback.h"
#include "base/check_is_test.h"
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/not_fatal_until.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/types/optional_ref.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_applications/commands/web_app_uninstall_command.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_integrity_block_data.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_storage_location.h"
#include "chrome/browser/web_applications/jobs/uninstall/remove_install_source_job.h"
#include "chrome/browser/web_applications/jobs/uninstall/remove_install_url_job.h"
#include "chrome/browser/web_applications/jobs/uninstall/remove_web_app_job.h"
#include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/browser/web_applications/os_integration/web_app_shortcuts_menu.h"
#include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
#include "chrome/browser/web_applications/proto/web_app_install_state.pb.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_command_manager.h"
#include "chrome/browser/web_applications/web_app_constants.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_icon_generator.h"
#include "chrome/browser/web_applications/web_app_icon_manager.h"
#include "chrome/browser/web_applications/web_app_id_constants.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_install_utils.h"
#include "chrome/browser/web_applications/web_app_origin_association_manager.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_registry_update.h"
#include "chrome/browser/web_applications/web_app_sync_bridge.h"
#include "chrome/browser/web_applications/web_app_translation_manager.h"
#include "chrome/browser/web_applications/web_app_ui_manager.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/sync/protocol/web_app_specifics.pb.h"
#include "components/webapps/browser/uninstall_result_code.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/skia/include/core/SkColor.h"
#include "url/origin.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/system_web_apps/types/system_web_app_data.h"
#endif

namespace web_app {
namespace {

// Overwrite the user display mode if the install source indicates a
// user-initiated installation
bool ShouldInstallOverwriteUserDisplayMode(
    webapps::WebappInstallSource source) {}

#if BUILDFLAG(IS_CHROMEOS)
// When web apps are added to sync on ChromeOS the value of
// user_display_mode_default should be set in certain cases to avoid poor sync
// install states on pre-M122 devices and non-CrOS devices with particular web
// apps.
// See switch for specific cases being mitigated against.
// See go/udm-desync#bookmark=id.cg753kjyrruo for design doc.
// TODO(b/320771282): Add automated tests.
void ApplyUserDisplayModeSyncMitigations(
    const WebAppInstallFinalizer::FinalizeOptions& options,
    WebApp& web_app) {
  // Guaranteed by EnsureAppsHaveUserDisplayModeForCurrentPlatform().
  CHECK(web_app.sync_proto().has_user_display_mode_cros(),
        base::NotFatalUntil::M125);

  // Don't mitigate installations from sync, this is only for installs that will
  // be newly uploaded to sync.
  if (options.install_surface == webapps::WebappInstallSource::SYNC) {
    return;
  }

  // Only mitigate if web app is being added to sync.
  if (options.source != WebAppManagement::Type::kSync) {
    return;
  }

  // Don't override existing default-platform value.
  if (web_app.sync_proto().has_user_display_mode_default()) {
    return;
  }

  sync_pb::WebAppSpecifics sync_proto = web_app.sync_proto();

  switch (web_app.sync_proto().user_display_mode_cros()) {
    case sync_pb::WebAppSpecifics_UserDisplayMode_BROWSER:
      if (!base::FeatureList::IsEnabled(
              kUserDisplayModeSyncBrowserMitigation)) {
        return;
      }

      // Pre-M122 CrOS devices use the user_display_mode_default sync field
      // instead of user_display_mode_cros. If user_display_mode_default is ever
      // unset they will fallback to using kStandalone even if
      // user_display_mode_cros is set to kBrowser. This mitigation ensures
      // user_display_mode_default is set to kBrowser for these devices. Example
      // user journey:
      // - Install web app as browser shortcut on post-M122 CrOS device.
      // - Sync installation to pre-M122 CrOS device.
      // - Check that it is synced as a browser shortcut.
      // TODO(b/321617981): Remove when there are sufficiently few pre-M122 CrOS
      // devices in circulation.
      sync_proto.set_user_display_mode_default(
          sync_pb::WebAppSpecifics_UserDisplayMode_BROWSER);
      break;

    case sync_pb::WebAppSpecifics_UserDisplayMode_STANDALONE: {
      if (!base::FeatureList::IsEnabled(
              kUserDisplayModeSyncStandaloneMitigation)) {
        return;
      }

      // Ensure standalone averse apps don't get defaulted to kStandalone on
      // non-CrOS devices via sync.
      // Example user journey:
      // - Install Google Docs as a standalone web app.
      // - Sync installation to non-CrOS device.
      // - Check that it is synced as a browser shortcut.
      // TODO(b/321617972): Remove when Windows/Mac/Linux support for tabbed web
      // apps is in sufficient circulation.
      bool is_standalone_averse_app = web_app.app_id() == kGoogleDocsAppId ||
                                      web_app.app_id() == kGoogleSheetsAppId ||
                                      web_app.app_id() == kGoogleSlidesAppId;
      if (!is_standalone_averse_app) {
        break;
      }
      sync_proto.set_user_display_mode_default(
          sync_pb::WebAppSpecifics_UserDisplayMode_BROWSER);
      break;
    }

    case sync_pb::WebAppSpecifics_UserDisplayMode_TABBED:
      // This can only be reached when kDesktopPWAsTabStripSettings is enabled,
      // this is only for testing and is planned to be removed.
      return;
    case sync_pb::WebAppSpecifics_UserDisplayMode_UNSPECIFIED:
      // Ignore unknown UserDisplayMode values.
      return;
  }

  web_app.SetSyncProto(std::move(sync_proto));
}
#endif  // BUILDFLAG(IS_CHROMEOS)

}  // namespace

WebAppInstallFinalizer::FinalizeOptions::IwaOptions::IwaOptions(
    IsolatedWebAppStorageLocation location,
    std::optional<IsolatedWebAppIntegrityBlockData> integrity_block_data)
    :{}

WebAppInstallFinalizer::FinalizeOptions::IwaOptions::~IwaOptions() = default;

WebAppInstallFinalizer::FinalizeOptions::IwaOptions::IwaOptions(
    const IwaOptions&) = default;

WebAppInstallFinalizer::FinalizeOptions::FinalizeOptions(
    webapps::WebappInstallSource install_surface)
    :{}

WebAppInstallFinalizer::FinalizeOptions::~FinalizeOptions() = default;

WebAppInstallFinalizer::FinalizeOptions::FinalizeOptions(
    const FinalizeOptions&) = default;

WebAppInstallFinalizer::WebAppInstallFinalizer(Profile* profile)
    :{}

WebAppInstallFinalizer::~WebAppInstallFinalizer() = default;

void WebAppInstallFinalizer::FinalizeInstall(
    const WebAppInstallInfo& web_app_info,
    const FinalizeOptions& options,
    InstallFinalizedCallback callback) {}

void WebAppInstallFinalizer::OnOriginAssociationValidated(
    WebAppInstallInfo web_app_info,
    FinalizeOptions options,
    InstallFinalizedCallback callback,
    webapps::AppId app_id,
    ScopeExtensions validated_scope_extensions) {}

bool WebAppInstallFinalizer::CanReparentTab(const webapps::AppId& app_id,
                                            bool shortcut_created) const {}

void WebAppInstallFinalizer::ReparentTab(const webapps::AppId& app_id,
                                         bool shortcut_created,
                                         content::WebContents* web_contents) {}

void WebAppInstallFinalizer::FinalizeUpdate(
    const WebAppInstallInfo& web_app_info,
    InstallFinalizedCallback callback) {}

void WebAppInstallFinalizer::SetProvider(base::PassKey<WebAppProvider>,
                                         WebAppProvider& provider) {}

void WebAppInstallFinalizer::Start() {}

void WebAppInstallFinalizer::Shutdown() {}

void WebAppInstallFinalizer::UpdateIsolationDataAndResetPendingUpdateInfo(
    WebApp* web_app,
    const IsolatedWebAppStorageLocation& location,
    const base::Version& version,
    std::optional<IsolatedWebAppIntegrityBlockData> integrity_block_data) {}

void WebAppInstallFinalizer::SetWebAppManifestFieldsAndWriteData(
    const WebAppInstallInfo& web_app_info,
    std::unique_ptr<WebApp> web_app,
    CommitCallback commit_callback,
    bool skip_icon_writes_on_download_failure) {}

void WebAppInstallFinalizer::WriteTranslations(
    const webapps::AppId& app_id,
    const base::flat_map<std::string, blink::Manifest::TranslationItem>&
        translations,
    CommitCallback commit_callback,
    bool success) {}

void WebAppInstallFinalizer::CommitToSyncBridge(std::unique_ptr<WebApp> web_app,
                                                CommitCallback commit_callback,
                                                bool success) {}

void WebAppInstallFinalizer::OnDatabaseCommitCompletedForInstall(
    InstallFinalizedCallback callback,
    webapps::AppId app_id,
    FinalizeOptions finalize_options,
    bool success) {}

void WebAppInstallFinalizer::OnInstallHooksFinished(
    InstallFinalizedCallback callback,
    webapps::AppId app_id) {}

void WebAppInstallFinalizer::NotifyWebAppInstalledWithOsHooks(
    webapps::AppId app_id) {}

bool WebAppInstallFinalizer::ShouldUpdateOsHooks(const webapps::AppId& app_id) {}

void WebAppInstallFinalizer::OnDatabaseCommitCompletedForUpdate(
    InstallFinalizedCallback callback,
    webapps::AppId app_id,
    std::string old_name,
    FileHandlerUpdateAction file_handlers_need_os_update,
    const WebAppInstallInfo& web_app_info,
    bool success) {}

void WebAppInstallFinalizer::OnUpdateHooksFinished(
    InstallFinalizedCallback callback,
    webapps::AppId app_id) {}

void WebAppInstallFinalizer::WriteExternalConfigMapInfo(
    WebApp& web_app,
    WebAppManagement::Type source,
    bool is_placeholder,
    GURL install_url,
    std::vector<std::string> additional_policy_ids) {}

FileHandlerUpdateAction WebAppInstallFinalizer::GetFileHandlerUpdateAction(
    const webapps::AppId& app_id,
    const WebAppInstallInfo& new_web_app_info) {}

}  // namespace web_app