blob: 2183b131559383e97951bec60ddffca61693e4f4 [file] [log] [blame]
// Copyright 2019 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.
#ifndef CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_TASK_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_TASK_H_
#include "base/check_op.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/browser/web_applications/web_app_icon_downloader.h"
#include "chrome/browser/web_applications/web_app_icon_manager.h"
#include "chrome/browser/web_applications/web_app_id.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
#include "components/services/app_service/public/cpp/file_handler.h"
#include "components/services/app_service/public/cpp/protocol_handler_info.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace webapps {
struct InstallableData;
enum class InstallResultCode;
}
namespace web_app {
class WebAppIconManager;
class WebAppInstallFinalizer;
class WebAppRegistrar;
class WebAppSyncBridge;
class WebAppUiManager;
class OsIntegrationManager;
enum class AppIdentityUpdate;
enum class IconsDownloadedResult;
struct IconDiff;
// This enum is recorded by UMA, the numeric values must not change.
enum ManifestUpdateResult {
kNoAppInScope = 0,
kThrottled = 1,
kWebContentsDestroyed = 2,
kAppUninstalling = 3,
kAppIsPlaceholder = 4,
kAppUpToDate = 5,
kAppNotEligible = 6,
kAppUpdateFailed = 7,
kAppUpdated = 8,
kAppIsSystemWebApp = 9,
kIconDownloadFailed = 10,
kIconReadFromDiskFailed = 11,
kAppIdMismatch = 12,
kAppAssociationsUpdateFailed = 13,
kAppAssociationsUpdated = 14,
kMaxValue = kAppAssociationsUpdated,
};
enum IconDiffResult : uint32_t {
NO_CHANGE_DETECTED = 0,
// A mismatch was detected between what was downloaded and what is on disk.
// This might mean that a size has been removed or added, and it could mean
// both.
MISMATCHED_IMAGE_SIZES = 1 << 1,
// At least one icon was found to have changed. Note: Used only if the diff
// process stops when it encounters the first mismatch. If, instead, it is
// allowed to continue, a more detailed results will be returned (see flags
// below).
ONE_OR_MORE_ICONS_CHANGED = 1 << 2,
// The launcher icon is changing. Note: that the launcher icon size is
// platform-specific and that this flag is only set if the diff process is
// allowed to continue to the end (doesn't stop as soon as it finds a
// change).
LAUNCHER_ICON_CHANGED = 1 << 3,
// The launcher icon is changing. Note: that the install icon size is
// platform-specific and that this flag is only set if the diff process is
// allowed to continue to the end (doesn't stop as soon as it finds a
// change).
INSTALL_ICON_CHANGED = 1 << 4,
// An icon, other than the launcher/install icon changed. Note: that this flag
// is only set if the diff process is allowed to continue to the end (doesn't
// stop as soon as it finds a change).
UNIMPORTANT_ICON_CHANGED = 1 << 5,
};
// A structure to keep track of the differences found while comparing icons
// on disk to what has been downloaded.
struct IconDiff {
public:
IconDiff() = default;
explicit IconDiff(uint32_t results) { diff_results = results; }
IconDiff(const SkBitmap& before_icon,
const SkBitmap& after_icon,
uint32_t results) {
before = before_icon;
after = after_icon;
diff_results = results;
}
// Returns true iff an icon change was detected (not matter how
// insignificant).
bool mismatch() const { return diff_results != NO_CHANGE_DETECTED; }
// Returns true iff the mismatch should result in app identity dlg being
// shown.
bool requires_app_identity_check() const {
return ((diff_results & LAUNCHER_ICON_CHANGED) != 0) ||
((diff_results & INSTALL_ICON_CHANGED) != 0);
}
// Keeps track of all the differences discovered in the icon set.
uint32_t diff_results = NO_CHANGE_DETECTED;
// The original image. Only valid if a single icon is changing.
SkBitmap before;
// The changed image. Only valid if a single icon is changing.
SkBitmap after;
};
// Returns whether any differences were found in the images on disk and what has
// been downloaded. The |disk_icon_bitmaps| and |disk_icon_info| parameters
// represent the bits on disk and the associated size info (respectively). Same
// with |downloaded_icon_bitmaps| and |downloaded_icon_info|, which covers the
// downloaded icon set. If |end_when_mismatch_detected| is true, the diff
// process will stop when it encounters the first mismatch. Otherwise, it the
// IconDiff returned will cover all the differences found.
IconDiff HaveIconBitmapsChanged(
const IconBitmaps& disk_icon_bitmaps,
const IconBitmaps& downloaded_icon_bitmaps,
const std::vector<apps::IconInfo>& disk_icon_info,
const std::vector<apps::IconInfo>& downloaded_icon_info,
bool end_when_mismatch_detected);
// Checks whether the installed web app associated with a given WebContents has
// out of date manifest data and triggers an update if so.
// Owned and managed by |ManifestUpdateManager|.
//
// High level check procedure:
// - Wait for page to load.
// - Load the page's manifest. Abort if none found.
// - Check a hard coded set of manifest fields for differences to what's stored
// locally. Abort if no differences.
// - Check if the app ID has changed, abort if so.
// - Require user confirmation for changes to the app name.
// - Wait for all app windows to be closed.
// - Reinstall the web app using the fetched data.
class ManifestUpdateTask final
: public base::SupportsWeakPtr<ManifestUpdateTask>,
public content::WebContentsObserver {
public:
using UpdatePendingCallback = base::OnceCallback<void(const GURL& url)>;
using StoppedCallback = base::OnceCallback<void(const ManifestUpdateTask&,
ManifestUpdateResult result)>;
// Sets a |callback| for testing code to get notified when a manifest update
// is needed and there is a PWA window preventing the update from proceeding.
// Only called once, iff the update process determines that waiting is needed.
static void SetUpdatePendingCallbackForTesting(
UpdatePendingCallback callback);
static bool& BypassWindowCloseWaitingForTesting();
ManifestUpdateTask(const GURL& url,
const AppId& app_id,
content::WebContents* web_contents,
StoppedCallback stopped_callback,
bool hang_for_testing,
WebAppRegistrar& registrar,
WebAppIconManager& icon_manager,
WebAppUiManager* ui_manager,
WebAppInstallFinalizer* install_finalizer,
OsIntegrationManager& os_integration_manager,
WebAppSyncBridge* sync_bridge);
~ManifestUpdateTask() override;
const GURL& url() const { return url_; }
const AppId& app_id() const { return app_id_; }
// content::WebContentsObserver:
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
void WebContentsDestroyed() override;
private:
enum class Stage {
kPendingPageLoad,
kPendingInstallableData,
kPendingIconDownload,
kPendingIconReadFromDisk,
kPendingAppIdentityCheck,
kPendingWindowsClosed,
kPendingMaybeReadExistingIcons,
kPendingInstallation,
kPendingAssociationsUpdate,
};
void OnDidGetInstallableData(const webapps::InstallableData& data);
bool IsUpdateNeededForManifest() const;
void LoadAndCheckIconContents();
void OnIconsDownloaded(IconsDownloadedResult result,
IconsMap icons_map,
DownloadedIconsHttpResults icons_http_results);
void OnAllIconsRead(IconsMap downloaded_icons_map,
IconBitmaps disk_icon_bitmaps);
void OnPostAppIdentityUpdateCheck(
AppIdentityUpdate app_identity_update_allowed);
IconDiff IsUpdateNeededForIconContents(
const IconBitmaps& disk_icon_bitmaps) const;
void OnAllShortcutsMenuIconsRead(
ShortcutsMenuIconBitmaps disk_shortcuts_menu_icons);
bool IsUpdateNeededForShortcutsMenuIconsContents(
const ShortcutsMenuIconBitmaps& disk_shortcuts_menu_icons) const;
bool IsUpdateNeededForWebAppOriginAssociations() const;
void NoManifestUpdateRequired();
void OnWebAppOriginAssociationsUpdated(bool success);
void UpdateAfterWindowsClose();
void OnAllAppWindowsClosed();
void OnExistingIconsRead(IconBitmaps icon_bitmaps);
void OnInstallationComplete(const AppId& app_id,
webapps::InstallResultCode code,
OsHooksErrors os_hooks_errors);
void DestroySelf(ManifestUpdateResult result);
WebAppRegistrar& registrar_;
WebAppIconManager& icon_manager_;
WebAppUiManager& ui_manager_;
WebAppInstallFinalizer& install_finalizer_;
OsIntegrationManager& os_integration_manager_;
raw_ptr<WebAppSyncBridge> sync_bridge_ = nullptr;
Stage stage_;
absl::optional<WebAppInstallInfo> install_info_;
absl::optional<WebAppIconDownloader> icon_downloader_;
// Two KeepAlive objects, to make sure in progress manifest updates survive
// during shutdown.
std::unique_ptr<ScopedKeepAlive> keep_alive_;
std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive_;
const GURL url_;
const AppId app_id_;
StoppedCallback stopped_callback_;
bool hang_for_testing_ = false;
bool app_identity_update_allowed_ = false;
#if DCHECK_IS_ON()
raw_ptr<bool> destructor_called_ptr_ = nullptr;
#endif
};
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_TASK_H_