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

WebApp: Implement WebAppSyncBridge in full.

This code is disabled by default behind kDesktopPWAsWithoutExtensions and
kDesktopPWAsUSS base features.

- Implement WebAppSyncBridge::MergeSyncData and ApplySyncChanges.
- Implement "Local changes" propagation to change_processor.

Unit tests and browser tests will be added later in a follow up CL.
An MVP implementation of the bridge needed first.

This CL follows Chrome Sync's Model API doc
https://chromium.googlesource.com/chromium/src/+/HEAD/docs/sync/model_api.md

In next CLs:
Implement sync-initiated installs and uninstalls.

TBR=alancutter@chromium.org

Bug: 860583
Change-Id: I65d3cae6f47dd8fc8fdbe2c7cfb2ed13012f90f3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1830494Reviewed-by: default avatarAlexey Baskakov <loyso@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Commit-Queue: Alexey Baskakov <loyso@chromium.org>
Cr-Commit-Position: refs/heads/master@{#704482}
parent 92809357
...@@ -45,6 +45,7 @@ source_set("web_applications") { ...@@ -45,6 +45,7 @@ source_set("web_applications") {
"web_app_registry_update.h", "web_app_registry_update.h",
"web_app_sync_bridge.cc", "web_app_sync_bridge.cc",
"web_app_sync_bridge.h", "web_app_sync_bridge.h",
"web_app_sync_install_delegate.h",
] ]
deps = [ deps = [
......
...@@ -19,6 +19,9 @@ enum Type { ...@@ -19,6 +19,9 @@ enum Type {
kSystem = kMinValue, kSystem = kMinValue,
kPolicy, kPolicy,
kWebAppStore, kWebAppStore,
// We sync only regular user-installed apps from the open web. For
// user-installed apps without overlaps this is the only source that will be
// set.
kSync, kSync,
kDefault, kDefault,
kMaxValue kMaxValue
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "chrome/browser/web_applications/test/test_web_app_database_factory.h" #include "chrome/browser/web_applications/test/test_web_app_database_factory.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_registry_update.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_sync_bridge.h"
...@@ -21,7 +22,7 @@ void TestWebAppRegistryController::SetUp(Profile* profile) { ...@@ -21,7 +22,7 @@ void TestWebAppRegistryController::SetUp(Profile* profile) {
mutable_registrar_ = std::make_unique<WebAppRegistrarMutable>(profile); mutable_registrar_ = std::make_unique<WebAppRegistrarMutable>(profile);
sync_bridge_ = std::make_unique<WebAppSyncBridge>( sync_bridge_ = std::make_unique<WebAppSyncBridge>(
profile, database_factory_.get(), mutable_registrar_.get(), profile, database_factory_.get(), mutable_registrar_.get(), this,
mock_processor_.CreateForwardingProcessor()); mock_processor_.CreateForwardingProcessor());
ON_CALL(processor(), IsTrackingMetadata()) ON_CALL(processor(), IsTrackingMetadata())
...@@ -51,6 +52,12 @@ void TestWebAppRegistryController::UnregisterAll() { ...@@ -51,6 +52,12 @@ void TestWebAppRegistryController::UnregisterAll() {
update->DeleteApp(app_id); update->DeleteApp(app_id);
} }
void TestWebAppRegistryController::InstallWebAppsAfterSync(
std::vector<WebApp*> web_apps) {}
void TestWebAppRegistryController::UninstallWebAppsAfterSync(
std::vector<std::unique_ptr<WebApp>> web_apps) {}
void TestWebAppRegistryController::DestroySubsystems() { void TestWebAppRegistryController::DestroySubsystems() {
mutable_registrar_.reset(); mutable_registrar_.reset();
sync_bridge_.reset(); sync_bridge_.reset();
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_registrar.h" #include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_sync_install_delegate.h"
#include "components/sync/model/mock_model_type_change_processor.h" #include "components/sync/model/mock_model_type_change_processor.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
...@@ -20,7 +21,7 @@ class TestWebAppDatabaseFactory; ...@@ -20,7 +21,7 @@ class TestWebAppDatabaseFactory;
class WebAppSyncBridge; class WebAppSyncBridge;
class WebApp; class WebApp;
class TestWebAppRegistryController { class TestWebAppRegistryController : public SyncInstallDelegate {
public: public:
TestWebAppRegistryController(); TestWebAppRegistryController();
~TestWebAppRegistryController(); ~TestWebAppRegistryController();
...@@ -35,6 +36,11 @@ class TestWebAppRegistryController { ...@@ -35,6 +36,11 @@ class TestWebAppRegistryController {
void UnregisterApp(const AppId& app_id); void UnregisterApp(const AppId& app_id);
void UnregisterAll(); void UnregisterAll();
// SyncInstallDelegate:
void InstallWebAppsAfterSync(std::vector<WebApp*> web_apps) override;
void UninstallWebAppsAfterSync(
std::vector<std::unique_ptr<WebApp>> web_apps) override;
void DestroySubsystems(); void DestroySubsystems();
TestWebAppDatabaseFactory& database_factory() { return *database_factory_; } TestWebAppDatabaseFactory& database_factory() { return *database_factory_; }
......
...@@ -33,6 +33,9 @@ class WebApp { ...@@ -33,6 +33,9 @@ class WebApp {
const GURL& scope() const { return scope_; } const GURL& scope() const { return scope_; }
const base::Optional<SkColor>& theme_color() const { return theme_color_; } const base::Optional<SkColor>& theme_color() const { return theme_color_; }
blink::mojom::DisplayMode display_mode() const { return display_mode_; } blink::mojom::DisplayMode display_mode() const { return display_mode_; }
// Locally installed apps have shortcuts installed on various UI surfaces.
// If app isn't locally installed, it is excluded from UIs and only listed as
// a part of user's app library.
bool is_locally_installed() const { return is_locally_installed_; } bool is_locally_installed() const { return is_locally_installed_; }
// Sync-initiated installation produces a sync placeholder app awaiting for // Sync-initiated installation produces a sync placeholder app awaiting for
// full installation process. The sync placeholder app has only app_id, // full installation process. The sync placeholder app has only app_id,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "chrome/browser/web_applications/web_app_registry_update.h" #include "chrome/browser/web_applications/web_app_registry_update.h"
#include "components/sync/base/model_type.h" #include "components/sync/base/model_type.h"
#include "components/sync/model/metadata_batch.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_error.h"
#include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
...@@ -50,14 +51,18 @@ void WebAppDatabase::BeginTransaction() { ...@@ -50,14 +51,18 @@ void WebAppDatabase::BeginTransaction() {
write_batch_ = store_->CreateWriteBatch(); write_batch_ = store_->CreateWriteBatch();
} }
void WebAppDatabase::CommitTransaction(const RegistryUpdateData& update_data, void WebAppDatabase::CommitTransaction(
CompletionCallback callback) { const RegistryUpdateData& update_data,
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
CompletionCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(opened_); DCHECK(opened_);
DCHECK(write_batch_); DCHECK(write_batch_);
DCHECK(!update_data.IsEmpty()); DCHECK(!update_data.IsEmpty());
write_batch_->TakeMetadataChangesFrom(std::move(metadata_change_list));
for (const std::unique_ptr<WebApp>& web_app : update_data.apps_to_create) { for (const std::unique_ptr<WebApp>& web_app : update_data.apps_to_create) {
auto proto = CreateWebAppProto(*web_app); auto proto = CreateWebAppProto(*web_app);
write_batch_->WriteData(web_app->app_id(), proto->SerializeAsString()); write_batch_->WriteData(web_app->app_id(), proto->SerializeAsString());
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
namespace syncer { namespace syncer {
class ModelError; class ModelError;
class MetadataBatch; class MetadataBatch;
class MetadataChangeList;
} // namespace syncer } // namespace syncer
namespace web_app { namespace web_app {
...@@ -49,8 +50,10 @@ class WebAppDatabase { ...@@ -49,8 +50,10 @@ class WebAppDatabase {
using CompletionCallback = base::OnceCallback<void(bool success)>; using CompletionCallback = base::OnceCallback<void(bool success)>;
// There can be only 1 transaction at a time. // There can be only 1 transaction at a time.
void BeginTransaction(); void BeginTransaction();
void CommitTransaction(const RegistryUpdateData& update_data, void CommitTransaction(
CompletionCallback callback); const RegistryUpdateData& update_data,
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
CompletionCallback callback);
void CancelTransaction(); void CancelTransaction();
// Exposed for testing. // Exposed for testing.
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "chrome/browser/web_applications/components/web_app_constants.h" #include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/components/web_app_data_retriever.h" #include "chrome/browser/web_applications/components/web_app_data_retriever.h"
#include "chrome/browser/web_applications/components/web_app_utils.h" #include "chrome/browser/web_applications/components/web_app_utils.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_install_task.h" #include "chrome/browser/web_applications/web_app_install_task.h"
#include "chrome/common/web_application_info.h" #include "chrome/common/web_application_info.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
...@@ -154,6 +155,18 @@ void WebAppInstallManager::Shutdown() { ...@@ -154,6 +155,18 @@ void WebAppInstallManager::Shutdown() {
web_contents_.reset(); web_contents_.reset();
} }
void WebAppInstallManager::InstallWebAppsAfterSync(
std::vector<WebApp*> web_apps) {
// TODO(crbug.com/860583): Implement sync-initiated app installs.
NOTIMPLEMENTED();
}
void WebAppInstallManager::UninstallWebAppsAfterSync(
std::vector<std::unique_ptr<WebApp>> web_apps) {
// TODO(crbug.com/860583): Implement sync-initiated app uninstalls.
NOTIMPLEMENTED();
}
void WebAppInstallManager::SetUrlLoaderForTesting( void WebAppInstallManager::SetUrlLoaderForTesting(
std::unique_ptr<WebAppUrlLoader> url_loader) { std::unique_ptr<WebAppUrlLoader> url_loader) {
url_loader_ = std::move(url_loader); url_loader_ = std::move(url_loader);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "chrome/browser/web_applications/components/install_manager.h" #include "chrome/browser/web_applications/components/install_manager.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/browser/web_applications/components/web_app_url_loader.h" #include "chrome/browser/web_applications/components/web_app_url_loader.h"
#include "chrome/browser/web_applications/web_app_sync_install_delegate.h"
class Profile; class Profile;
...@@ -29,7 +30,8 @@ enum class InstallResultCode; ...@@ -29,7 +30,8 @@ enum class InstallResultCode;
class WebAppDataRetriever; class WebAppDataRetriever;
class WebAppInstallTask; class WebAppInstallTask;
class WebAppInstallManager final : public InstallManager { class WebAppInstallManager final : public InstallManager,
public SyncInstallDelegate {
public: public:
explicit WebAppInstallManager(Profile* profile); explicit WebAppInstallManager(Profile* profile);
~WebAppInstallManager() override; ~WebAppInstallManager() override;
...@@ -64,6 +66,11 @@ class WebAppInstallManager final : public InstallManager { ...@@ -64,6 +66,11 @@ class WebAppInstallManager final : public InstallManager {
OnceInstallCallback callback) override; OnceInstallCallback callback) override;
void Shutdown() override; void Shutdown() override;
// For the new USS-based system only. SyncInstallDelegate:
void InstallWebAppsAfterSync(std::vector<WebApp*> web_apps) override;
void UninstallWebAppsAfterSync(
std::vector<std::unique_ptr<WebApp>> web_apps) override;
using DataRetrieverFactory = using DataRetrieverFactory =
base::RepeatingCallback<std::unique_ptr<WebAppDataRetriever>()>; base::RepeatingCallback<std::unique_ptr<WebAppDataRetriever>()>;
void SetDataRetrieverFactoryForTesting( void SetDataRetrieverFactoryForTesting(
......
...@@ -170,7 +170,8 @@ void WebAppProvider::CreateWebAppsSubsystems(Profile* profile) { ...@@ -170,7 +170,8 @@ void WebAppProvider::CreateWebAppsSubsystems(Profile* profile) {
auto mutable_registrar = std::make_unique<WebAppRegistrarMutable>(profile); auto mutable_registrar = std::make_unique<WebAppRegistrarMutable>(profile);
sync_bridge = std::make_unique<WebAppSyncBridge>( sync_bridge = std::make_unique<WebAppSyncBridge>(
profile, database_factory_.get(), mutable_registrar.get()); profile, database_factory_.get(), mutable_registrar.get(),
install_manager_.get());
// Upcast to read-only WebAppRegistrar. // Upcast to read-only WebAppRegistrar.
registrar = std::move(mutable_registrar); registrar = std::move(mutable_registrar);
......
...@@ -5,16 +5,20 @@ ...@@ -5,16 +5,20 @@
#include "chrome/browser/web_applications/web_app_sync_bridge.h" #include "chrome/browser/web_applications/web_app_sync_bridge.h"
#include <memory> #include <memory>
#include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/optional.h" #include "base/optional.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/browser/web_applications/components/web_app_helpers.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.h"
#include "chrome/browser/web_applications/web_app_database_factory.h" #include "chrome/browser/web_applications/web_app_database_factory.h"
#include "chrome/browser/web_applications/web_app_registry_update.h" #include "chrome/browser/web_applications/web_app_registry_update.h"
#include "chrome/browser/web_applications/web_app_sync_install_delegate.h"
#include "chrome/common/channel_info.h" #include "chrome/common/channel_info.h"
#include "components/sync/base/model_type.h" #include "components/sync/base/model_type.h"
#include "components/sync/base/report_unrecoverable_error.h" #include "components/sync/base/report_unrecoverable_error.h"
...@@ -36,27 +40,71 @@ std::unique_ptr<syncer::EntityData> CreateSyncEntityData(const WebApp& app) { ...@@ -36,27 +40,71 @@ std::unique_ptr<syncer::EntityData> CreateSyncEntityData(const WebApp& app) {
auto entity_data = std::make_unique<syncer::EntityData>(); auto entity_data = std::make_unique<syncer::EntityData>();
entity_data->name = app.name(); entity_data->name = app.name();
sync_pb::WebAppSpecifics* specifics = sync_pb::WebAppSpecifics* sync_data =
entity_data->specifics.mutable_web_app(); entity_data->specifics.mutable_web_app();
specifics->set_launch_url(app.launch_url().spec()); sync_data->set_launch_url(app.launch_url().spec());
specifics->set_name(app.name()); sync_data->set_display_mode(ToWebAppSpecificsDisplayMode(app.display_mode()));
specifics->set_display_mode(ToWebAppSpecificsDisplayMode(app.display_mode())); sync_data->set_name(app.sync_data().name);
if (app.theme_color().has_value()) if (app.sync_data().theme_color.has_value())
specifics->set_theme_color(app.theme_color().value()); sync_data->set_theme_color(app.sync_data().theme_color.value());
return entity_data; return entity_data;
} }
void ApplySyncDataToApp(const sync_pb::WebAppSpecifics& sync_data,
WebApp* app) {
app->AddSource(Source::kSync);
// app_id is a hash of launch_url. Parse launch_url first:
GURL launch_url(sync_data.launch_url());
if (launch_url.is_empty() || !launch_url.is_valid()) {
DLOG(ERROR) << "ApplySyncDataToApp: launch_url parse error.";
return;
}
if (app->app_id() != GenerateAppIdFromURL(launch_url)) {
DLOG(ERROR) << "ApplySyncDataToApp: app_id doesn't match launch_url.";
return;
}
if (app->launch_url().is_empty()) {
app->SetLaunchUrl(std::move(launch_url));
} else if (app->launch_url() != launch_url) {
DLOG(ERROR)
<< "ApplySyncDataToApp: existing launch_url doesn't match launch_url.";
return;
}
// Always override display mode with a synced value.
app->SetDisplayMode(ToMojomDisplayMode(sync_data.display_mode()));
WebApp::SyncData parsed_sync_data;
parsed_sync_data.name = sync_data.name();
if (sync_data.has_theme_color())
parsed_sync_data.theme_color = sync_data.theme_color();
app->SetSyncData(parsed_sync_data);
}
bool AreAppsLocallyInstalledByDefault() {
#if defined(OS_CHROMEOS)
// On Chrome OS, sync always locally installs an app.
return true;
#else
return false;
#endif
}
} // namespace } // namespace
WebAppSyncBridge::WebAppSyncBridge( WebAppSyncBridge::WebAppSyncBridge(
Profile* profile, Profile* profile,
AbstractWebAppDatabaseFactory* database_factory, AbstractWebAppDatabaseFactory* database_factory,
WebAppRegistrarMutable* registrar) WebAppRegistrarMutable* registrar,
SyncInstallDelegate* install_delegate)
: WebAppSyncBridge( : WebAppSyncBridge(
profile, profile,
database_factory, database_factory,
registrar, registrar,
install_delegate,
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::WEB_APPS, syncer::WEB_APPS,
base::BindRepeating(&syncer::ReportUnrecoverableError, base::BindRepeating(&syncer::ReportUnrecoverableError,
...@@ -66,10 +114,12 @@ WebAppSyncBridge::WebAppSyncBridge( ...@@ -66,10 +114,12 @@ WebAppSyncBridge::WebAppSyncBridge(
Profile* profile, Profile* profile,
AbstractWebAppDatabaseFactory* database_factory, AbstractWebAppDatabaseFactory* database_factory,
WebAppRegistrarMutable* registrar, WebAppRegistrarMutable* registrar,
SyncInstallDelegate* install_delegate,
std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor) std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
: AppRegistryController(profile), : AppRegistryController(profile),
syncer::ModelTypeSyncBridge(std::move(change_processor)), syncer::ModelTypeSyncBridge(std::move(change_processor)),
registrar_(registrar) { registrar_(registrar),
install_delegate_(install_delegate) {
DCHECK(database_factory); DCHECK(database_factory);
DCHECK(registrar_); DCHECK(registrar_);
database_ = std::make_unique<WebAppDatabase>( database_ = std::make_unique<WebAppDatabase>(
...@@ -103,12 +153,14 @@ void WebAppSyncBridge::CommitUpdate( ...@@ -103,12 +153,14 @@ void WebAppSyncBridge::CommitUpdate(
CheckRegistryUpdateData(update->update_data()); CheckRegistryUpdateData(update->update_data());
registrar_->CountMutation();
std::unique_ptr<RegistryUpdateData> update_data = update->TakeUpdateData(); std::unique_ptr<RegistryUpdateData> update_data = update->TakeUpdateData();
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
CreateMetadataChangeList();
UpdateSync(*update_data, metadata_change_list.get());
database_->CommitTransaction( database_->CommitTransaction(
*update_data, *update_data, std::move(metadata_change_list),
base::BindOnce(&WebAppSyncBridge::OnDataWritten, base::BindOnce(&WebAppSyncBridge::OnDataWritten,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
...@@ -157,19 +209,73 @@ void WebAppSyncBridge::CheckRegistryUpdateData( ...@@ -157,19 +209,73 @@ void WebAppSyncBridge::CheckRegistryUpdateData(
#endif #endif
} }
void WebAppSyncBridge::UpdateRegistrar( std::vector<std::unique_ptr<WebApp>> WebAppSyncBridge::UpdateRegistrar(
std::unique_ptr<RegistryUpdateData> update_data) { std::unique_ptr<RegistryUpdateData> update_data) {
registrar_->CountMutation();
std::vector<std::unique_ptr<WebApp>> apps_unregistered;
for (std::unique_ptr<WebApp>& web_app : update_data->apps_to_create) { for (std::unique_ptr<WebApp>& web_app : update_data->apps_to_create) {
AppId app_id = web_app->app_id(); AppId app_id = web_app->app_id();
DCHECK(!registrar_->GetAppById(app_id)); DCHECK(!registrar_->GetAppById(app_id));
registrar_->registry().emplace(std::move(app_id), std::move(web_app)); registrar_->registry().emplace(std::move(app_id), std::move(web_app));
} }
// update_data->apps_to_update are ignored here because we do in-place
// updates.
for (const AppId& app_id : update_data->apps_to_delete) { for (const AppId& app_id : update_data->apps_to_delete) {
auto it = registrar_->registry().find(app_id); auto it = registrar_->registry().find(app_id);
DCHECK(it != registrar_->registry().end()); DCHECK(it != registrar_->registry().end());
apps_unregistered.push_back(std::move(it->second));
registrar_->registry().erase(it); registrar_->registry().erase(it);
} }
return apps_unregistered;
}
void WebAppSyncBridge::UpdateSync(
const RegistryUpdateData& update_data,
syncer::MetadataChangeList* metadata_change_list) {
// We don't block web app subsystems on WebAppSyncBridge::MergeSyncData: we
// call WebAppProvider::OnRegistryControllerReady() right after
// change_processor()->ModelReadyToSync. As a result, subsystems may produce
// some local changes between OnRegistryControllerReady and MergeSyncData.
// Return early in this case. The processor cannot do any useful metadata
// tracking until MergeSyncData is called:
if (!change_processor()->IsTrackingMetadata())
return;
for (const std::unique_ptr<WebApp>& app : update_data.apps_to_create) {
if (app->IsSynced()) {
change_processor()->Put(app->app_id(), CreateSyncEntityData(*app),
metadata_change_list);
}
}
// An app may obtain or may loose IsSynced flag without being deleted. We
// should conservatively include or exclude the app from the synced apps
// subset.
//
// TODO(loyso): Send an update to sync server only if any sync-specific
// data was changed. Implement some dirty flags in WebApp setter methods.
for (const WebApp* app : update_data.apps_to_update) {
if (app->IsSynced()) {
change_processor()->Put(app->app_id(), CreateSyncEntityData(*app),
metadata_change_list);
} else {
change_processor()->Delete(app->app_id(), metadata_change_list);
}
}
// We should unconditionally delete from sync (in case IsSynced flag was
// removed during the update).
for (const AppId& app_id : update_data.apps_to_delete) {
const WebApp* app = registrar_->GetAppById(app_id);
DCHECK(app);
change_processor()->Delete(app_id, metadata_change_list);
}
} }
void WebAppSyncBridge::OnDatabaseOpened( void WebAppSyncBridge::OnDatabaseOpened(
...@@ -195,6 +301,102 @@ void WebAppSyncBridge::ReportErrorToChangeProcessor( ...@@ -195,6 +301,102 @@ void WebAppSyncBridge::ReportErrorToChangeProcessor(
change_processor()->ReportError(error); change_processor()->ReportError(error);
} }
void WebAppSyncBridge::MergeLocalAppsToSync(
const syncer::EntityChangeList& entity_data,
syncer::MetadataChangeList* metadata_change_list) {
// Build a helper set of the sync server apps to speed up lookups. The
// flat_set will reuse the underlying memory of this vector. app_id is storage
// key.
std::vector<AppId> storage_keys;
storage_keys.reserve(entity_data.size());
for (const auto& change : entity_data)
storage_keys.push_back(change->storage_key());
// Sort only once.
base::flat_set<AppId> sync_server_apps(std::move(storage_keys));
for (const WebApp& app : registrar_->AllApps()) {
if (!app.IsSynced())
continue;
bool exists_remotely = sync_server_apps.contains(app.app_id());
if (!exists_remotely) {
change_processor()->Put(app.app_id(), CreateSyncEntityData(app),
metadata_change_list);
}
}
}
void WebAppSyncBridge::ApplySyncDataChange(
const syncer::EntityChange& change,
RegistryUpdateData* update_local_data) {
// app_id is storage key.
const AppId& app_id = change.storage_key();
WebApp* existing_web_app = registrar_->GetAppByIdMutable(app_id);
// Handle deletion first.
if (change.type() == syncer::EntityChange::ACTION_DELETE) {
if (!existing_web_app) {
DLOG(ERROR) << "ApplySyncDataChange error: no app to delete";
return;
}
existing_web_app->RemoveSource(Source::kSync);
if (existing_web_app->HasAnySources())
update_local_data->apps_to_update.insert(existing_web_app);
else
update_local_data->apps_to_delete.push_back(app_id);
return;
}
// Handle EntityChange::ACTION_ADD and EntityChange::ACTION_UPDATE.
DCHECK(change.data().specifics.has_web_app());
const sync_pb::WebAppSpecifics& specifics = change.data().specifics.web_app();
if (existing_web_app) {
// Any entities that appear in both sets must be merged.
ApplySyncDataToApp(specifics, existing_web_app);
// Preserve web_app->is_locally_installed user's choice here.
update_local_data->apps_to_update.insert(existing_web_app);
} else {
// Any remote entities that don’t exist locally must be written to local
// storage.
auto web_app = std::make_unique<WebApp>(app_id);
// Request a followup sync-initiated install for this placeholder to fetch
// full local data and all the icons.
web_app->SetIsSyncPlaceholder(true);
ApplySyncDataToApp(specifics, web_app.get());
// For a new app, automatically choose if we want to install it locally.
web_app->SetIsLocallyInstalled(AreAppsLocallyInstalledByDefault());
update_local_data->apps_to_create.push_back(std::move(web_app));
}
}
void WebAppSyncBridge::ApplySyncChangesToRegistrar(
std::unique_ptr<RegistryUpdateData> update_local_data) {
std::vector<WebApp*> apps_to_install;
for (const auto& web_app : update_local_data->apps_to_create)
apps_to_install.push_back(web_app.get());
std::vector<std::unique_ptr<WebApp>> apps_unregistered =
UpdateRegistrar(std::move(update_local_data));
// Do a full follow up install for all remote entities that don’t exist
// locally.
install_delegate_->InstallWebAppsAfterSync(std::move(apps_to_install));
// Do a full follow up uninstall for all deleted remote entities that exist
// locally and not needed by other sources. We need to clean up disk data
// (icons).
install_delegate_->UninstallWebAppsAfterSync(std::move(apps_unregistered));
}
std::unique_ptr<syncer::MetadataChangeList> std::unique_ptr<syncer::MetadataChangeList>
WebAppSyncBridge::CreateMetadataChangeList() { WebAppSyncBridge::CreateMetadataChangeList() {
return syncer::ModelTypeStore::WriteBatch::CreateMetadataChangeList(); return syncer::ModelTypeStore::WriteBatch::CreateMetadataChangeList();
...@@ -203,14 +405,42 @@ WebAppSyncBridge::CreateMetadataChangeList() { ...@@ -203,14 +405,42 @@ WebAppSyncBridge::CreateMetadataChangeList() {
base::Optional<syncer::ModelError> WebAppSyncBridge::MergeSyncData( base::Optional<syncer::ModelError> WebAppSyncBridge::MergeSyncData(
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
syncer::EntityChangeList entity_data) { syncer::EntityChangeList entity_data) {
NOTIMPLEMENTED(); DCHECK(change_processor()->IsTrackingMetadata());
auto update_local_data = std::make_unique<RegistryUpdateData>();
database_->BeginTransaction();
for (const auto& change : entity_data) {
DCHECK_NE(change->type(), syncer::EntityChange::ACTION_DELETE);
ApplySyncDataChange(*change, update_local_data.get());
}
MergeLocalAppsToSync(entity_data, metadata_change_list.get());
database_->CommitTransaction(
*update_local_data, std::move(metadata_change_list), base::DoNothing());
ApplySyncChangesToRegistrar(std::move(update_local_data));
return base::nullopt; return base::nullopt;
} }
base::Optional<syncer::ModelError> WebAppSyncBridge::ApplySyncChanges( base::Optional<syncer::ModelError> WebAppSyncBridge::ApplySyncChanges(
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
syncer::EntityChangeList entity_changes) { syncer::EntityChangeList entity_changes) {
NOTIMPLEMENTED(); DCHECK(change_processor()->IsTrackingMetadata());
auto update_local_data = std::make_unique<RegistryUpdateData>();
database_->BeginTransaction();
for (const auto& change : entity_changes)
ApplySyncDataChange(*change, update_local_data.get());
database_->CommitTransaction(
*update_local_data, std::move(metadata_change_list), base::DoNothing());
ApplySyncChangesToRegistrar(std::move(update_local_data));
return base::nullopt; return base::nullopt;
} }
......
...@@ -14,12 +14,14 @@ ...@@ -14,12 +14,14 @@
#include "chrome/browser/web_applications/components/app_registry_controller.h" #include "chrome/browser/web_applications/components/app_registry_controller.h"
#include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_registrar.h" #include "chrome/browser/web_applications/web_app_registrar.h"
#include "components/sync/model/entity_change.h"
#include "components/sync/model/model_type_sync_bridge.h" #include "components/sync/model/model_type_sync_bridge.h"
class Profile; class Profile;
namespace syncer { namespace syncer {
class MetadataBatch; class MetadataBatch;
class MetadataChangeList;
class ModelError; class ModelError;
class ModelTypeChangeProcessor; class ModelTypeChangeProcessor;
} // namespace syncer } // namespace syncer
...@@ -27,6 +29,7 @@ class ModelTypeChangeProcessor; ...@@ -27,6 +29,7 @@ class ModelTypeChangeProcessor;
namespace web_app { namespace web_app {
class AbstractWebAppDatabaseFactory; class AbstractWebAppDatabaseFactory;
class SyncInstallDelegate;
class WebAppDatabase; class WebAppDatabase;
class WebAppRegistryUpdate; class WebAppRegistryUpdate;
struct RegistryUpdateData; struct RegistryUpdateData;
...@@ -38,12 +41,14 @@ class WebAppSyncBridge : public AppRegistryController, ...@@ -38,12 +41,14 @@ class WebAppSyncBridge : public AppRegistryController,
public: public:
WebAppSyncBridge(Profile* profile, WebAppSyncBridge(Profile* profile,
AbstractWebAppDatabaseFactory* database_factory, AbstractWebAppDatabaseFactory* database_factory,
WebAppRegistrarMutable* registrar); WebAppRegistrarMutable* registrar,
SyncInstallDelegate* install_delegate);
// Tests may inject mocks using this ctor. // Tests may inject mocks using this ctor.
WebAppSyncBridge( WebAppSyncBridge(
Profile* profile, Profile* profile,
AbstractWebAppDatabaseFactory* database_factory, AbstractWebAppDatabaseFactory* database_factory,
WebAppRegistrarMutable* registrar, WebAppRegistrarMutable* registrar,
SyncInstallDelegate* install_delegate,
std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor); std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
~WebAppSyncBridge() override; ~WebAppSyncBridge() override;
...@@ -64,8 +69,15 @@ class WebAppSyncBridge : public AppRegistryController, ...@@ -64,8 +69,15 @@ class WebAppSyncBridge : public AppRegistryController,
private: private:
void CheckRegistryUpdateData(const RegistryUpdateData& update_data) const; void CheckRegistryUpdateData(const RegistryUpdateData& update_data) const;
// Update the in-memory model.
void UpdateRegistrar(std::unique_ptr<RegistryUpdateData> update_data); // Update the in-memory model. Returns unregistered apps which may be
// disposed.
std::vector<std::unique_ptr<WebApp>> UpdateRegistrar(
std::unique_ptr<RegistryUpdateData> update_data);
// Update the remote sync server.
void UpdateSync(const RegistryUpdateData& update_data,
syncer::MetadataChangeList* metadata_change_list);
void OnDatabaseOpened(base::OnceClosure callback, void OnDatabaseOpened(base::OnceClosure callback,
Registry registry, Registry registry,
...@@ -74,6 +86,17 @@ class WebAppSyncBridge : public AppRegistryController, ...@@ -74,6 +86,17 @@ class WebAppSyncBridge : public AppRegistryController,
void ReportErrorToChangeProcessor(const syncer::ModelError& error); void ReportErrorToChangeProcessor(const syncer::ModelError& error);
// Any local entities that don’t exist remotely must be provided to sync.
void MergeLocalAppsToSync(const syncer::EntityChangeList& entity_data,
syncer::MetadataChangeList* metadata_change_list);
void ApplySyncDataChange(const syncer::EntityChange& change,
RegistryUpdateData* update_local_data);
// Update registrar and Install/Uninstall missing/excessive local apps.
void ApplySyncChangesToRegistrar(
std::unique_ptr<RegistryUpdateData> update_local_data);
// syncer::ModelTypeSyncBridge: // syncer::ModelTypeSyncBridge:
std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList() std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
override; override;
...@@ -90,6 +113,7 @@ class WebAppSyncBridge : public AppRegistryController, ...@@ -90,6 +113,7 @@ class WebAppSyncBridge : public AppRegistryController,
std::unique_ptr<WebAppDatabase> database_; std::unique_ptr<WebAppDatabase> database_;
WebAppRegistrarMutable* const registrar_; WebAppRegistrarMutable* const registrar_;
SyncInstallDelegate* const install_delegate_;
bool is_in_update_ = false; bool is_in_update_ = false;
......
// 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_WEB_APP_SYNC_INSTALL_DELEGATE_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_INSTALL_DELEGATE_H_
#include <memory>
#include <vector>
namespace web_app {
class WebApp;
// WebAppSyncBridge delegates sync-initiated installs and uninstalls using
// this interface.
class SyncInstallDelegate {
public:
virtual ~SyncInstallDelegate() = default;
// |web_apps| are already registered and owned by the registrar.
virtual void InstallWebAppsAfterSync(std::vector<WebApp*> web_apps) = 0;
// |web_apps| are already unregistered and not owned by the registrar.
virtual void UninstallWebAppsAfterSync(
std::vector<std::unique_ptr<WebApp>> web_apps) = 0;
};
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_INSTALL_DELEGATE_H_
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