Commit fc2a7f58 authored by Alexey Baskakov's avatar Alexey Baskakov Committed by Commit Bot

WebApp: Implement migration of bookmark apps to new web apps.

The new WebAppMigrationManager is responsible for any migration-related
code.

WebAppMigrationManager::StartDatabaseMigration performs the offline
migration of all bookmark apps to new web apps registry.

We do the offline migration only once, before the initial sync.

Any additional apps arriving after the initial sync should be installed
via WebAppSyncBridge::CommitUpdate() "as if" a user installs them.
This will be explained in go/chrome-bmo-migration doc and implemented
as a follow up CL.

WebAppMigrationManagerBrowserTest demonstrates some new techniques
on how to write integration tests:
- PRE test and content::IsPreTest().
- URLLoaderInterceptor instead of EmbeddedTestServer.

More tests and test/data/ will follow:
- DatabaseMigration_FullManifest and manifest_full_data.json.
- A set of apps to test the queue.

Bug: 1020037
Change-Id: I0038d321932a72deeb00fd21cd3171f1b8ee0fcb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2014340
Commit-Queue: Alexey Baskakov <loyso@chromium.org>
Reviewed-by: default avatarAlan Cutter <alancutter@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Cr-Commit-Position: refs/heads/master@{#742076}
parent 18cf8144
......@@ -4,11 +4,41 @@
#include "chrome/browser/ui/web_applications/test/ssl_test_utils.h"
#include "base/atomic_sequence_num.h"
#include "base/time/time.h"
#include "chrome/browser/ssl/ssl_browsertest_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "components/security_state/core/features.h"
#include "components/security_state/core/security_state.h"
#include "crypto/rsa_private_key.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "net/ssl/ssl_info.h"
namespace {
// NSS requires that serial numbers be unique even for the same issuer;
// as all fake certificates will contain the same issuer name, it's
// necessary to ensure the serial number is unique, as otherwise
// NSS will fail to parse.
base::AtomicSequenceNumber g_serial_number;
scoped_refptr<net::X509Certificate> CreateFakeCert() {
std::unique_ptr<crypto::RSAPrivateKey> unused_key;
std::string cert_der;
if (!net::x509_util::CreateKeyAndSelfSignedCert(
"CN=Error", static_cast<uint32_t>(g_serial_number.GetNext()),
base::Time::Now() - base::TimeDelta::FromMinutes(5),
base::Time::Now() + base::TimeDelta::FromMinutes(5), &unused_key,
&cert_der)) {
return nullptr;
}
return net::X509Certificate::CreateFromBytes(cert_der.data(),
cert_der.size());
}
} // namespace
namespace web_app {
......@@ -32,4 +62,8 @@ void CheckMixedContentFailedToLoad(Browser* browser) {
ssl_test_util::AuthState::NONE);
}
void CreateFakeSslInfoCertificate(net::SSLInfo* ssl_info) {
ssl_info->cert = ssl_info->unverified_cert = CreateFakeCert();
}
} // namespace web_app
......@@ -7,6 +7,10 @@
class Browser;
namespace net {
class SSLInfo;
}
namespace web_app {
// Checks that the active tab's authentication state indicates insecure content.
......@@ -16,6 +20,8 @@ void CheckMixedContentLoaded(Browser* browser);
// content is shown.
void CheckMixedContentFailedToLoad(Browser* browser);
void CreateFakeSslInfoCertificate(net::SSLInfo* ssl_info);
} // namespace web_app
#endif // CHROME_BROWSER_UI_WEB_APPLICATIONS_TEST_SSL_TEST_UTILS_H_
......@@ -217,6 +217,7 @@ source_set("web_applications_browser_tests") {
"manifest_update_manager_browsertest.cc",
"pending_app_manager_impl_browsertest.cc",
"web_app_icon_manager_browsertest.cc",
"web_app_migration_manager_browsertest.cc",
]
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
......@@ -224,6 +225,7 @@ source_set("web_applications_browser_tests") {
deps = [
":common",
":web_applications",
":web_applications_on_extensions",
":web_applications_on_extensions_test_support",
":web_applications_test_support",
"//chrome/app:command_ids",
......@@ -237,6 +239,8 @@ source_set("web_applications_browser_tests") {
# web_applications set.
source_set("web_applications_on_extensions") {
sources = [
"web_app_migration_manager.cc",
"web_app_migration_manager.h",
"web_app_provider.cc",
"web_app_provider.h",
"web_app_provider_factory.cc",
......@@ -252,6 +256,7 @@ source_set("web_applications_on_extensions") {
"//chrome/common",
"//components/keyed_service/content",
"//components/pref_registry:pref_registry",
"//components/sync",
"//extensions/browser",
]
}
......
// 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/web_applications/web_app_migration_manager.h"
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_database.h"
#include "chrome/browser/web_applications/web_app_database_factory.h"
#include "chrome/browser/web_applications/web_app_icon_manager.h"
#include "chrome/browser/web_applications/web_app_registry_update.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/model/metadata_change_list.h"
#include "components/sync/model/model_error.h"
#include "components/sync/model/model_type_store.h"
namespace web_app {
WebAppMigrationManager::WebAppMigrationManager(
Profile* profile,
AbstractWebAppDatabaseFactory* database_factory,
WebAppIconManager* web_app_icon_manager)
: bookmark_app_registrar_(profile),
bookmark_app_registry_controller_(profile),
bookmark_app_icon_manager_(profile),
database_factory_(database_factory),
web_app_icon_manager_(web_app_icon_manager) {
database_ = std::make_unique<WebAppDatabase>(
database_factory_,
base::BindRepeating(&WebAppMigrationManager::ReportDatabaseError,
base::Unretained(this)));
}
WebAppMigrationManager::~WebAppMigrationManager() = default;
void WebAppMigrationManager::StartDatabaseMigration(
MigrationCompletedCallback migration_completed_callback) {
DCHECK(database_);
migration_completed_callback_ = std::move(migration_completed_callback);
// Open LevelDB first. The extension system behind
// BookmarkAppRegistryController is already started in parallel.
database_->OpenDatabase(
base::BindOnce(&WebAppMigrationManager::OnWebAppDatabaseOpened,
weak_ptr_factory_.GetWeakPtr()));
}
void WebAppMigrationManager::OnWebAppDatabaseOpened(
Registry web_app_registry,
std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
if (metadata_batch->GetModelTypeState().initial_sync_done()) {
// If initial sync is done, then WebAppSyncBridge::MergeSyncData was already
// called once. All the migrated entities are already listed in sync
// metadata. Any additional apps from this point in time should be installed
// via WebAppSyncBridge::CommitUpdate() "as if" a user installs them.
CloseDatabaseAndCallCallback(/*success=*/true);
return;
}
// Wait for the Extensions System to be ready.
bookmark_app_registry_controller_.Init(base::BindOnce(
&WebAppMigrationManager::OnBookmarkAppRegistryReady,
weak_ptr_factory_.GetWeakPtr(), std::move(web_app_registry)));
}
void WebAppMigrationManager::OnBookmarkAppRegistryReady(
Registry web_app_registry) {
bookmark_app_ids_ = bookmark_app_registrar_.GetAppIds();
// Remove bookmark app ids already listed in the web app registry.
base::EraseIf(bookmark_app_ids_, [&web_app_registry](const AppId& app_id) {
return base::Contains(web_app_registry, app_id);
});
// Migrate icons first, the registry data (the LevelDB transaction) last.
next_app_id_iterator_ = bookmark_app_ids_.begin();
MigrateNextBookmarkAppIcons();
}
void WebAppMigrationManager::MigrateNextBookmarkAppIcons() {
if (next_app_id_iterator_ == bookmark_app_ids_.end()) {
MigrateBookmarkAppsRegistry();
return;
}
const AppId& app_id = *next_app_id_iterator_;
++next_app_id_iterator_;
bookmark_app_icon_manager_.ReadAllIcons(
app_id, base::BindOnce(&WebAppMigrationManager::OnBookmarkAppIconsRead,
weak_ptr_factory_.GetWeakPtr(), app_id));
}
void WebAppMigrationManager::OnBookmarkAppIconsRead(
const AppId& app_id,
std::map<SquareSizePx, SkBitmap> icon_bitmaps) {
if (icon_bitmaps.empty()) {
DLOG(ERROR) << "Read bookmark app icons failed.";
MigrateNextBookmarkAppIcons();
return;
}
web_app_icon_manager_->WriteData(
app_id, std::move(icon_bitmaps),
base::BindOnce(&WebAppMigrationManager::OnWebAppIconsWritten,
weak_ptr_factory_.GetWeakPtr()));
}
void WebAppMigrationManager::OnWebAppIconsWritten(bool success) {
if (!success)
DLOG(ERROR) << "Write web app icons failed.";
MigrateNextBookmarkAppIcons();
}
void WebAppMigrationManager::MigrateBookmarkAppInstallSource(
const AppId& app_id,
WebApp* web_app) {
bool is_arc = bookmark_app_registrar_.HasExternalAppWithInstallSource(
app_id, ExternalInstallSource::kArc);
bool is_policy = bookmark_app_registrar_.HasExternalAppWithInstallSource(
app_id, ExternalInstallSource::kExternalPolicy);
bool is_default = bookmark_app_registrar_.HasExternalAppWithInstallSource(
app_id, ExternalInstallSource::kInternalDefault) ||
bookmark_app_registrar_.HasExternalAppWithInstallSource(
app_id, ExternalInstallSource::kExternalDefault);
bool is_system = bookmark_app_registrar_.HasExternalAppWithInstallSource(
app_id, ExternalInstallSource::kSystemInstalled);
if (is_default)
web_app->AddSource(Source::kDefault);
if (is_policy)
web_app->AddSource(Source::kPolicy);
if (is_system)
web_app->AddSource(Source::kSystem);
if (is_arc)
web_app->AddSource(Source::kWebAppStore);
if (!bookmark_app_registrar_.HasExternalApp(app_id))
web_app->AddSource(Source::kSync);
DCHECK(web_app->HasAnySources());
}
void WebAppMigrationManager::MigrateBookmarkAppFileHandlers(const AppId& app_id,
WebApp* web_app) {
NOTIMPLEMENTED();
// TODO(crbug.com/1020037): Convert
// bookmark_app_file_handler_manager.GetAllFileHandlers(app_id) to
// WebApp::FileHandlers representation.
WebApp::FileHandlers file_handlers;
web_app->SetFileHandlers(std::move(file_handlers));
}
std::unique_ptr<WebApp> WebAppMigrationManager::MigrateBookmarkApp(
const AppId& app_id) {
auto web_app = std::make_unique<WebApp>(app_id);
web_app->SetName(bookmark_app_registrar_.GetAppShortName(app_id));
web_app->SetDescription(bookmark_app_registrar_.GetAppDescription(app_id));
web_app->SetLaunchUrl(bookmark_app_registrar_.GetAppLaunchURL(app_id));
base::Optional<GURL> scope = bookmark_app_registrar_.GetAppScope(app_id);
if (scope)
web_app->SetScope(*scope);
web_app->SetThemeColor(bookmark_app_registrar_.GetAppThemeColor(app_id));
web_app->SetDisplayMode(bookmark_app_registrar_.GetAppDisplayMode(app_id));
web_app->SetUserDisplayMode(
bookmark_app_registrar_.GetAppUserDisplayMode(app_id));
web_app->SetIsLocallyInstalled(
bookmark_app_registrar_.IsLocallyInstalled(app_id));
web_app->SetIconInfos(bookmark_app_registrar_.GetAppIconInfos(app_id));
web_app->SetDownloadedIconSizes(
bookmark_app_registrar_.GetAppDownloadedIconSizes(app_id));
WebApp::SyncData sync_data;
sync_data.name = bookmark_app_registrar_.GetAppShortName(app_id);
sync_data.theme_color = bookmark_app_registrar_.GetAppThemeColor(app_id);
web_app->SetSyncData(std::move(sync_data));
MigrateBookmarkAppFileHandlers(app_id, web_app.get());
MigrateBookmarkAppInstallSource(app_id, web_app.get());
return web_app;
}
void WebAppMigrationManager::MigrateBookmarkAppsRegistry() {
DCHECK(database_);
if (bookmark_app_ids_.empty()) {
CloseDatabaseAndCallCallback(/*success=*/true);
return;
}
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
syncer::ModelTypeStore::WriteBatch::CreateMetadataChangeList();
RegistryUpdateData update_data;
update_data.apps_to_create.reserve(bookmark_app_ids_.size());
for (const AppId& app_id : bookmark_app_ids_) {
std::unique_ptr<WebApp> web_app = MigrateBookmarkApp(app_id);
update_data.apps_to_create.push_back(std::move(web_app));
}
database_->Write(
update_data, std::move(metadata_change_list),
base::BindOnce(&WebAppMigrationManager::OnWebAppRegistryWritten,
weak_ptr_factory_.GetWeakPtr()));
}
void WebAppMigrationManager::OnWebAppRegistryWritten(bool success) {
if (!success)
DLOG(ERROR) << "Web app registry commit failed.";
CloseDatabaseAndCallCallback(success);
}
void WebAppMigrationManager::ReportDatabaseError(
const syncer::ModelError& error) {
DLOG(ERROR) << "Web app database error. " << error.ToString();
CloseDatabaseAndCallCallback(/*success=*/false);
}
void WebAppMigrationManager::CloseDatabaseAndCallCallback(bool success) {
// Close the database.
database_ = nullptr;
if (migration_completed_callback_)
std::move(migration_completed_callback_).Run(success);
}
} // namespace web_app
// 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.
#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_MIGRATION_MANAGER_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_MIGRATION_MANAGER_H_
#include <memory>
#include <vector>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/web_applications/components/web_app_id.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_registry_controller.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/common/web_application_info.h"
namespace syncer {
class ModelError;
class MetadataBatch;
} // namespace syncer
namespace web_app {
class AbstractWebAppDatabaseFactory;
class WebAppDatabase;
class WebAppIconManager;
// Migrates all bookmark apps to new web apps registry.
class WebAppMigrationManager {
public:
WebAppMigrationManager(Profile* profile,
AbstractWebAppDatabaseFactory* database_factory,
WebAppIconManager* web_app_icon_manager);
WebAppMigrationManager(const WebAppMigrationManager&) = delete;
WebAppMigrationManager& operator=(const WebAppMigrationManager&) = delete;
~WebAppMigrationManager();
using MigrationCompletedCallback = base::OnceCallback<void(bool success)>;
void StartDatabaseMigration(
MigrationCompletedCallback migration_completed_callback);
private:
void OnWebAppDatabaseOpened(
Registry web_app_registry,
std::unique_ptr<syncer::MetadataBatch> metadata_batch);
void OnBookmarkAppRegistryReady(Registry web_app_registry);
// Migrates next bookmark app in |bookmark_app_ids_| queue or starts
// the registry migration if the queue is empty.
void MigrateNextBookmarkAppIcons();
void OnBookmarkAppIconsRead(const AppId& app_id,
std::map<SquareSizePx, SkBitmap> icon_bitmaps);
void OnWebAppIconsWritten(bool success);
void MigrateBookmarkAppInstallSource(const AppId& app_id, WebApp* web_app);
void MigrateBookmarkAppFileHandlers(const AppId& app_id, WebApp* web_app);
std::unique_ptr<WebApp> MigrateBookmarkApp(const AppId& app_id);
void MigrateBookmarkAppsRegistry();
void OnWebAppRegistryWritten(bool success);
void ReportDatabaseError(const syncer::ModelError& error);
void CloseDatabaseAndCallCallback(bool success);
extensions::BookmarkAppRegistrar bookmark_app_registrar_;
extensions::BookmarkAppRegistryController bookmark_app_registry_controller_;
extensions::BookmarkAppIconManager bookmark_app_icon_manager_;
AbstractWebAppDatabaseFactory* const database_factory_;
WebAppIconManager* const web_app_icon_manager_;
std::unique_ptr<WebAppDatabase> database_;
// A queue of bookmark app ids to be migrated.
std::vector<AppId> bookmark_app_ids_;
// Current bookmark app id which icons are being migrated.
std::vector<AppId>::const_iterator next_app_id_iterator_;
MigrationCompletedCallback migration_completed_callback_;
base::WeakPtrFactory<WebAppMigrationManager> weak_ptr_factory_{this};
};
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_MIGRATION_MANAGER_H_
// 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/web_applications/web_app_migration_manager.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/installable/installable_metrics.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/web_applications/test/ssl_test_utils.h"
#include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
#include "chrome/browser/web_applications/components/app_icon_manager.h"
#include "chrome/browser/web_applications/components/app_registrar.h"
#include "chrome/browser/web_applications/components/app_shortcut_manager.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/browser/web_applications/components/web_app_id.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_launcher.h"
#include "content/public/test/url_loader_interceptor.h"
#include "net/ssl/ssl_info.h"
namespace web_app {
namespace {
constexpr char kBaseDataDir[] = "chrome/test/data/banners";
// start_url in manifest.json matches navigation url for the simple
// manifest_test_page.html.
constexpr char kSimpleManifestStartUrl[] =
"https://example.org/manifest_test_page.html";
// Performs blocking IO operations.
base::FilePath GetDataFilePath(const base::FilePath& relative_path,
bool* path_exists) {
base::ScopedAllowBlockingForTesting allow_io;
base::FilePath root_path;
CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path));
base::FilePath path = root_path.Append(relative_path);
*path_exists = base::PathExists(path);
return path;
}
} // namespace
class WebAppMigrationManagerBrowserTest : public InProcessBrowserTest {
public:
WebAppMigrationManagerBrowserTest() {
if (content::IsPreTest()) {
scoped_feature_list_.InitAndDisableFeature(
features::kDesktopPWAsWithoutExtensions);
} else {
scoped_feature_list_.InitAndEnableFeature(
features::kDesktopPWAsWithoutExtensions);
}
}
~WebAppMigrationManagerBrowserTest() override = default;
WebAppMigrationManagerBrowserTest(const WebAppMigrationManagerBrowserTest&) =
delete;
WebAppMigrationManagerBrowserTest& operator=(
const WebAppMigrationManagerBrowserTest&) = delete;
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
// We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since
// a stable app_id across tests requires stable origin, whereas
// EmbeddedTestServer serves content on a random port.
url_loader_interceptor_ =
std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating(
[](content::URLLoaderInterceptor::RequestParams* params) -> bool {
std::string relative_request = base::StrCat(
{kBaseDataDir, params->url_request.url.path_piece()});
base::FilePath relative_path =
base::FilePath().AppendASCII(relative_request);
bool path_exists = false;
base::FilePath path =
GetDataFilePath(relative_path, &path_exists);
if (!path_exists)
return /*intercepted=*/false;
// Provide fake SSLInfo to avoid NOT_FROM_SECURE_ORIGIN error in
// InstallableManager::GetData().
net::SSLInfo ssl_info;
CreateFakeSslInfoCertificate(&ssl_info);
content::URLLoaderInterceptor::WriteResponse(
path, params->client.get(), /*headers=*/nullptr, ssl_info);
return /*intercepted=*/true;
}));
}
void TearDownOnMainThread() override {
url_loader_interceptor_.reset();
InProcessBrowserTest::TearDownOnMainThread();
}
AppId InstallWebAppAsUserViaOmnibox() {
chrome::SetAutoAcceptPWAInstallConfirmationForTesting(true);
chrome::SetAutoAcceptBookmarkAppDialogForTesting(
/*auto_accept=*/true,
/*auto_open_in_window=*/true);
provider().shortcut_manager().SuppressShortcutsForTesting();
AppId app_id;
base::RunLoop run_loop;
bool started = CreateWebAppFromManifest(
browser()->tab_strip_model()->GetActiveWebContents(),
WebappInstallSource::OMNIBOX_INSTALL_ICON,
base::BindLambdaForTesting(
[&](const AppId& installed_app_id, InstallResultCode code) {
EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall);
app_id = installed_app_id;
run_loop.Quit();
}));
EXPECT_TRUE(started);
run_loop.Run();
return app_id;
}
WebAppProvider& provider() {
WebAppProvider* provider = WebAppProvider::Get(browser()->profile());
DCHECK(provider);
return *provider;
}
void AwaitRegistryReady() {
base::RunLoop run_loop;
provider().on_registry_ready().Post(FROM_HERE, run_loop.QuitClosure());
run_loop.Run();
}
private:
std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_;
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(WebAppMigrationManagerBrowserTest,
PRE_DatabaseMigration_SimpleManifest) {
ui_test_utils::NavigateToURL(browser(), GURL{kSimpleManifestStartUrl});
AppId app_id = InstallWebAppAsUserViaOmnibox();
EXPECT_EQ(GenerateAppIdFromURL(GURL{kSimpleManifestStartUrl}), app_id);
EXPECT_TRUE(provider().registrar().AsBookmarkAppRegistrar());
EXPECT_FALSE(provider().registrar().AsWebAppRegistrar());
EXPECT_TRUE(provider().registrar().IsInstalled(app_id));
}
IN_PROC_BROWSER_TEST_F(WebAppMigrationManagerBrowserTest,
DatabaseMigration_SimpleManifest) {
AwaitRegistryReady();
AppId app_id = GenerateAppIdFromURL(GURL{kSimpleManifestStartUrl});
EXPECT_TRUE(provider().registrar().IsInstalled(app_id));
WebAppRegistrar* registrar = provider().registrar().AsWebAppRegistrar();
ASSERT_TRUE(registrar);
EXPECT_FALSE(provider().registrar().AsBookmarkAppRegistrar());
const WebApp* web_app = registrar->GetAppById(app_id);
ASSERT_TRUE(web_app);
EXPECT_EQ("Manifest test app", web_app->name());
EXPECT_EQ(DisplayMode::kStandalone, web_app->display_mode());
const std::vector<SquareSizePx> icon_sizes_in_px = {32, 48, 64, 96, 128,
144, 192, 256, 512};
EXPECT_EQ(icon_sizes_in_px, web_app->downloaded_icon_sizes());
base::RunLoop run_loop;
provider().icon_manager().ReadIcons(
app_id, web_app->downloaded_icon_sizes(),
base::BindLambdaForTesting(
[&](std::map<SquareSizePx, SkBitmap> icon_bitmaps) {
EXPECT_EQ(9u, icon_bitmaps.size());
for (auto& size_px_and_bitmap : icon_bitmaps) {
SquareSizePx size_px = size_px_and_bitmap.first;
EXPECT_TRUE(base::Contains(icon_sizes_in_px, size_px));
SkBitmap bitmap = size_px_and_bitmap.second;
EXPECT_FALSE(bitmap.empty());
EXPECT_EQ(size_px, bitmap.width());
EXPECT_EQ(size_px, bitmap.height());
}
run_loop.Quit();
}));
run_loop.Run();
}
// TODO(crbug.com/1020037): Test policy installed bookmark apps with an external
// install source to cover
// WebAppMigrationManager::MigrateBookmarkAppInstallSource() logic.
} // namespace web_app
......@@ -32,6 +32,7 @@
#include "chrome/browser/web_applications/web_app_icon_manager.h"
#include "chrome/browser/web_applications/web_app_install_finalizer.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_migration_manager.h"
#include "chrome/browser/web_applications/web_app_provider_factory.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_shortcut_manager.h"
......@@ -155,6 +156,16 @@ void WebAppProvider::Shutdown() {
}
void WebAppProvider::StartImpl() {
if (migration_manager_) {
migration_manager_->StartDatabaseMigration(
base::BindOnce(&WebAppProvider::OnDatabaseMigrationCompleted,
weak_ptr_factory_.GetWeakPtr()));
} else {
OnDatabaseMigrationCompleted(/*success=*/true);
}
}
void WebAppProvider::OnDatabaseMigrationCompleted(bool success) {
StartRegistryController();
}
......@@ -194,6 +205,8 @@ void WebAppProvider::CreateWebAppsSubsystems(Profile* profile) {
file_handler_manager_ = std::make_unique<WebAppFileHandlerManager>(profile);
shortcut_manager_ = std::make_unique<WebAppShortcutManager>(
profile, icon_manager.get(), file_handler_manager_.get());
migration_manager_ = std::make_unique<WebAppMigrationManager>(
profile, database_factory_.get(), icon_manager.get());
// Upcast to unified subsystem types:
registrar_ = std::move(registrar);
......
......@@ -44,6 +44,7 @@ class WebAppUiManager;
// Forward declarations for new extension-independent subsystems.
class WebAppDatabaseFactory;
class WebAppMigrationManager;
// Connects Web App features, such as the installation of default and
// policy-managed web apps, with Profiles (as WebAppProvider is a
......@@ -93,6 +94,7 @@ class WebAppProvider : public WebAppProviderBase {
protected:
virtual void StartImpl();
void OnDatabaseMigrationCompleted(bool success);
// Create subsystems that work with either BMO and Extension backends.
void CreateCommonSubsystems(Profile* profile);
......@@ -112,6 +114,8 @@ class WebAppProvider : public WebAppProviderBase {
// New extension-independent subsystems:
std::unique_ptr<WebAppDatabaseFactory> database_factory_;
// migration_manager_ can be nullptr if no migration needed.
std::unique_ptr<WebAppMigrationManager> migration_manager_;
// Generalized subsystems:
std::unique_ptr<AppRegistrar> registrar_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment