Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1078)

Unified Diff: chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc

Issue 2106663004: arc: Initial implemetation of Chrome sync for Arc packages. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Modify target Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc
diff --git a/chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc b/chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0ac54a217f137cc103b77b1cda30697e86e6ce05
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc
@@ -0,0 +1,430 @@
+// Copyright 2016 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/ui/app_list/arc/arc_package_syncable_service.h"
+
+#include <unordered_set>
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/app_list/arc/arc_package_syncable_service_factory.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "components/sync/api/sync_change_processor.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_merge_result.h"
+#include "components/sync/protocol/sync.pb.h"
+
+namespace arc {
+// TODO(lgcheng@) change VLOG(1) to VLOG(2).
+
+namespace {
+
+using syncer::SyncChange;
+using ArcSyncItem = ArcPackageSyncableService::SyncItem;
+
+std::unique_ptr<ArcSyncItem> CreateSyncItemFromSyncSpecifics(
+ const sync_pb::ArcPackageSpecifics& specifics) {
+ return base::MakeUnique<ArcSyncItem>(
+ specifics.package_name(), specifics.package_version(),
+ specifics.last_backup_android_id(), specifics.last_backup_time());
+}
+
+std::unique_ptr<ArcSyncItem> CreateSyncItemFromSyncData(
+ const syncer::SyncData& sync_data) {
+ const sync_pb::EntitySpecifics& entity_specifics = sync_data.GetSpecifics();
+ DCHECK(entity_specifics.has_arc_package());
+ const sync_pb::ArcPackageSpecifics& specifics =
+ entity_specifics.arc_package();
+
+ return CreateSyncItemFromSyncSpecifics(specifics);
+}
+
+void UpdateSyncSpecificsFromSyncItem(const ArcSyncItem* item,
+ sync_pb::ArcPackageSpecifics* specifics) {
+ DCHECK(item);
+ DCHECK(specifics);
+ specifics->set_package_name(item->package_name);
+ specifics->set_package_version(item->package_version);
+ specifics->set_last_backup_android_id(item->last_backup_android_id);
+ specifics->set_last_backup_time(item->last_backup_time);
+}
+
+syncer::SyncData GetSyncDataFromSyncItem(const ArcSyncItem* item) {
+ DCHECK(item);
+ sync_pb::EntitySpecifics specifics;
+ UpdateSyncSpecificsFromSyncItem(item, specifics.mutable_arc_package());
+ return syncer::SyncData::CreateLocalData(item->package_name,
+ item->package_name, specifics);
+}
+
+// Creates new syncItem from ArcAppListPrefs::PackageInfo
+std::unique_ptr<ArcSyncItem> CreateSyncItemFromPrefs(
+ std::unique_ptr<ArcAppListPrefs::PackageInfo> package_info) {
+ DCHECK(package_info);
+ return base::MakeUnique<ArcSyncItem>(
+ package_info->package_name, package_info->package_version,
+ package_info->last_backup_android_id, package_info->last_backup_time);
+}
+
+} // namespace
+
+// ArcPackageSyncableService::SyncItem
+ArcSyncItem::SyncItem(const std::string& package_name,
+ int32_t package_version,
+ int64_t last_backup_android_id,
+ int64_t last_backup_time)
+ : package_name(package_name),
+ package_version(package_version),
+ last_backup_android_id(last_backup_android_id),
+ last_backup_time(last_backup_time) {}
+
+// ArcPackageSyncableService public
+ArcPackageSyncableService::ArcPackageSyncableService(Profile* profile,
+ ArcAppListPrefs* prefs)
+ : profile_(profile),
+ sync_processor_(nullptr),
+ sync_error_handler_(nullptr),
+ prefs_(prefs) {
+ if (prefs_)
+ prefs_->AddObserver(this);
+}
+
+ArcPackageSyncableService::~ArcPackageSyncableService() {
+ if (prefs_)
+ prefs_->RemoveObserver(this);
+}
+
+// static
+ArcPackageSyncableService* ArcPackageSyncableService::Create(
+ Profile* profile,
+ ArcAppListPrefs* prefs) {
+ return new ArcPackageSyncableService(profile, prefs);
+}
+
+// static
+ArcPackageSyncableService* ArcPackageSyncableService::Get(
+ content::BrowserContext* context) {
+ return ArcPackageSyncableServiceFactory::GetForBrowserContext(context);
+}
+
+syncer::SyncMergeResult ArcPackageSyncableService::MergeDataAndStartSyncing(
+ syncer::ModelType type,
+ const syncer::SyncDataList& initial_sync_data,
+ std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
+ std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
+ DCHECK(sync_processor.get());
+ DCHECK(error_handler.get());
+ DCHECK_EQ(type, syncer::ARC_PACKAGE);
+ DCHECK(!sync_processor_.get());
+ sync_processor_ = std::move(sync_processor);
+ sync_error_handler_ = std::move(error_handler);
+
+ syncer::SyncMergeResult result = syncer::SyncMergeResult(type);
+
+ const std::vector<std::string> local_packages =
+ prefs_->GetPackagesFromPrefs();
+ const std::unordered_set<std::string> local_package_set(
+ local_packages.begin(), local_packages.end());
+
+ // Creates sync items from synced data.
+ for (const syncer::SyncData& sync_data : initial_sync_data) {
+ std::unique_ptr<ArcSyncItem> sync_item(
+ CreateSyncItemFromSyncData(sync_data));
+ const std::string& package_name = sync_item->package_name;
+ if (!ContainsKey(local_package_set, package_name)) {
+ InstallPackage(sync_item.get());
+ pending_install_items_[package_name] = std::move(sync_item);
+ } else {
+ // TODO(lgcheng@) may need to handle update exsiting package here.
+ sync_items_[package_name] = std::move(sync_item);
+ }
+ }
+
+ // Creates sync items for local unsynced packages.
+ syncer::SyncChangeList change_list;
+ for (const auto& local_package_name : local_packages) {
+ if (ContainsKey(sync_items_, local_package_name))
+ continue;
+
+ if (!ShouldSyncPackage(local_package_name))
+ continue;
+
+ std::unique_ptr<ArcSyncItem> sync_item(
+ CreateSyncItemFromPrefs(prefs_->GetPackage(local_package_name)));
+ change_list.push_back(SyncChange(FROM_HERE, SyncChange::ACTION_ADD,
+ GetSyncDataFromSyncItem(sync_item.get())));
+ sync_items_[local_package_name] = std::move(sync_item);
+ }
+ sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
+ return result;
+}
+
+void ArcPackageSyncableService::StopSyncing(syncer::ModelType type) {
+ DCHECK_EQ(type, syncer::ARC_PACKAGE);
+
+ // TODO(lgcheng@) Remove this log.
+ VLOG(1) << "Stop Syncing.";
+
+ sync_processor_.reset();
+ sync_error_handler_.reset();
+
+ sync_items_.clear();
+ pending_install_items_.clear();
+ pending_uninstall_items_.clear();
+}
+
+syncer::SyncDataList ArcPackageSyncableService::GetAllSyncData(
+ syncer::ModelType type) const {
+ DCHECK_EQ(type, syncer::ARC_PACKAGE);
+
+ syncer::SyncDataList list;
+ for (const auto& item : sync_items_)
+ list.emplace_back(GetSyncDataFromSyncItem(item.second.get()));
+
+ for (const auto& item : pending_install_items_)
+ list.emplace_back(GetSyncDataFromSyncItem(item.second.get()));
+
+ return list;
+}
+
+syncer::SyncError ArcPackageSyncableService::ProcessSyncChanges(
+ const tracked_objects::Location& from_here,
+ const syncer::SyncChangeList& change_list) {
+ if (!sync_processor_.get()) {
+ return syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
+ "Arc package syncable service is not started.",
+ syncer::ARC_PACKAGE);
+ }
+
+ for (const auto& change : change_list) {
+ VLOG(2) << this << " Change: "
+ << change.sync_data().GetSpecifics().arc_package().package_name()
+ << " (" << change.change_type() << ")";
+
+ if (change.change_type() == SyncChange::ACTION_ADD ||
+ change.change_type() == SyncChange::ACTION_UPDATE) {
+ ProcessSyncItemSpecifics(change.sync_data().GetSpecifics().arc_package());
+ } else if (change.change_type() == SyncChange::ACTION_DELETE) {
+ DeleteSyncItemSpecifics(change.sync_data().GetSpecifics().arc_package());
+ } else {
+ VLOG(2) << "Invalid sync change";
+ }
+ }
+
+ return syncer::SyncError();
+}
+
+bool ArcPackageSyncableService::SyncStarted() {
+ if (sync_processor_.get())
+ return true;
+ if (flare_.is_null()) {
+ VLOG(1) << this << ": SyncStarted: Flare.";
+ flare_ = sync_start_util::GetFlareForSyncableService(profile_->GetPath());
+ flare_.Run(syncer::ARC_PACKAGE);
+ }
+ return false;
+}
+
+// ArcPackageSyncableService private
+void ArcPackageSyncableService::OnPackageRemoved(
+ const std::string& package_name) {
+ SyncItemMap::iterator delete_iter =
+ pending_uninstall_items_.find(package_name);
+ // TODO(lgcheng@) Remove this log.
+ VLOG(1) << "Package Removed:" << package_name;
+
+ // Pending uninstall item. Confirm uninstall.
+ if (delete_iter != pending_uninstall_items_.end()) {
+ pending_uninstall_items_.erase(delete_iter);
+ return;
+ }
+
+ SyncItemMap::iterator iter = sync_items_.find(package_name);
+ if (iter == sync_items_.end()) {
+ VLOG(2) << "Request to remove package which does not exist.";
+ return;
+ }
+
+ if (!SyncStarted()) {
+ VLOG(1) << "Request to send sync change when sync service is not started.";
+ return;
+ }
+ // TODO(lgcheng@) Remove this log.
+ VLOG(1) << "Sync change: Package Removed:" << package_name;
+
+ SyncChange sync_change(FROM_HERE, SyncChange::ACTION_DELETE,
+ GetSyncDataFromSyncItem(iter->second.get()));
+ sync_processor_->ProcessSyncChanges(FROM_HERE,
+ syncer::SyncChangeList(1, sync_change));
+
+ sync_items_.erase(iter);
+}
+
+void ArcPackageSyncableService::OnPackageInstalled(
+ const mojom::ArcPackageInfo& package_info) {
+ const std::string& package_name = package_info.package_name;
+ // TODO(lgcheng@) Remove this log.
+ VLOG(1) << "Package Installed:" << package_name;
+
+ if (!package_info.sync)
+ return;
+
+ SyncItemMap::iterator install_iter =
+ pending_install_items_.find(package_name);
+
+ // Pending install item. Confirm install.
+ if (install_iter != pending_install_items_.end()) {
+ sync_items_[package_name] = std::move(install_iter->second);
+ pending_install_items_.erase(install_iter);
+ return;
+ }
+
+ SyncItemMap::iterator iter = sync_items_.find(package_name);
+ if (iter != sync_items_.end()) {
+ VLOG(2) << "Request sync service to add new package which does exist.";
+ return;
+ }
+
+ SendSyncChange(package_info, SyncChange::ACTION_ADD);
+}
+
+void ArcPackageSyncableService::OnPackageModified(
+ const mojom::ArcPackageInfo& package_info) {
+ const std::string& package_name = package_info.package_name;
+ // TODO(lgcheng@) Remove this log.
+ VLOG(1) << "Package Updated:" << package_name;
+
+ if (!package_info.sync)
+ return;
+
+ SyncItemMap::iterator iter = sync_items_.find(package_name);
+ if (iter == sync_items_.end()) {
+ VLOG(2) << "Request sync service to update package which does not exist.";
+ return;
+ }
+
+ SendSyncChange(package_info, SyncChange::ACTION_UPDATE);
+}
+
+void ArcPackageSyncableService::SendSyncChange(
+ const mojom::ArcPackageInfo& package_info,
+ const syncer::SyncChange::SyncChangeType& sync_change_type) {
+ const std::string& package_name = package_info.package_name;
+
+ if (!SyncStarted()) {
+ VLOG(1) << "Request to send sync change when sync service is not started.";
+ return;
+ }
+
+ std::unique_ptr<ArcSyncItem> sync_item = base::MakeUnique<ArcSyncItem>(
+ package_info.package_name, package_info.package_version,
+ package_info.last_backup_android_id, package_info.last_backup_time);
+
+ // TODO(lgcheng@) Remove this log.
+ VLOG(1) << "Sync change: Package Added/Updated:" << package_name;
+
+ SyncChange sync_change(FROM_HERE, sync_change_type,
+ GetSyncDataFromSyncItem(sync_item.get()));
+ sync_processor_->ProcessSyncChanges(FROM_HERE,
+ syncer::SyncChangeList(1, sync_change));
+
+ sync_items_[package_name] = std::move(sync_item);
+}
+
+bool ArcPackageSyncableService::ProcessSyncItemSpecifics(
+ const sync_pb::ArcPackageSpecifics& specifics) {
+ const std::string& package_name = specifics.package_name();
+ if (package_name.empty()) {
+ VLOG(2) << "Add/Update Arc package item with empty package name";
+ return false;
+ }
+
+ SyncItemMap::const_iterator iter = sync_items_.find(package_name);
+ if (iter != sync_items_.end()) {
+ // TODO(lgcheng@) may need to create update exsiting package logic here.
+ return true;
+ }
+
+ SyncItemMap::const_iterator pending_iter =
+ pending_install_items_.find(package_name);
+ if (pending_iter != pending_install_items_.end()) {
+ // TODO(lgcheng@) may need to create update pending install package
+ // logic here.
+ return true;
+ }
+
+ std::unique_ptr<ArcSyncItem> sync_item(
+ CreateSyncItemFromSyncSpecifics(specifics));
+ InstallPackage(sync_item.get());
+ pending_install_items_[package_name] = std::move(sync_item);
+ return true;
+}
+
+bool ArcPackageSyncableService::DeleteSyncItemSpecifics(
+ const sync_pb::ArcPackageSpecifics& specifics) {
+ const std::string& package_name = specifics.package_name();
+ if (package_name.empty()) {
+ VLOG(2) << "Delete Arc package item with empty package name";
+ return false;
+ }
+
+ SyncItemMap::const_iterator delete_iter =
+ pending_install_items_.find(package_name);
+ // Ignore this this delete sync change. Package is pending uninstall.
+ if (delete_iter != pending_install_items_.end()) {
+ pending_install_items_.erase(delete_iter);
+ return true;
+ }
+
+ SyncItemMap::iterator iter = sync_items_.find(package_name);
+ if (iter != sync_items_.end()) {
+ UninstallPackage(iter->second.get());
+ pending_uninstall_items_[package_name] = std::move(iter->second);
+ sync_items_.erase(iter);
+ return true;
+ }
+ // TODO(lgcheng@) may need to handle the situation that the package is
+ // pending install.
+ return true;
+}
+
+void ArcPackageSyncableService::InstallPackage(const ArcSyncItem* sync_item) {
+ DCHECK(sync_item);
+ if (!prefs_ || !prefs_->app_instance_holder()->instance()) {
+ VLOG(2) << "Request to install package when bridge service is not ready: "
+ << sync_item->package_name << ".";
+ return;
+ }
+
+ mojom::ArcPackageInfo package;
+ package.package_name = sync_item->package_name;
+ package.package_version = sync_item->package_version;
+ package.last_backup_android_id = sync_item->last_backup_android_id;
+ package.last_backup_time = sync_item->last_backup_time;
+ package.sync = true;
+ prefs_->app_instance_holder()->instance()->InstallPackage(package.Clone());
+}
+
+void ArcPackageSyncableService::UninstallPackage(const ArcSyncItem* sync_item) {
+ DCHECK(sync_item);
+ if (!prefs_ || !prefs_->app_instance_holder()->instance()) {
+ VLOG(2) << "Request to uninstall package when bridge service is not ready: "
+ << sync_item->package_name << ".";
+ return;
+ }
+
+ prefs_->app_instance_holder()->instance()->UninstallPackage(
+ sync_item->package_name);
+}
+
+bool ArcPackageSyncableService::ShouldSyncPackage(
+ const std::string& package_name) const {
+ std::unique_ptr<ArcAppListPrefs::PackageInfo> package(
+ prefs_->GetPackage(package_name));
+ DCHECK(package.get());
+ return package->should_sync;
+}
+
+} // namespace arc

Powered by Google App Engine
This is Rietveld 408576698