Chromium Code Reviews| 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..c8b671fdc887afee2ea6597db6a535f3ac7be3e7 |
| --- /dev/null |
| +++ b/chrome/browser/ui/app_list/arc/arc_package_syncable_service.cc |
| @@ -0,0 +1,438 @@ |
| +// 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 "sync/api/sync_change_processor.h" |
| +#include "sync/api/sync_data.h" |
| +#include "sync/api/sync_merge_result.h" |
| +#include "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); |
| + |
| + // TODO(lgcheng@) Remove this log. |
| + VLOG(1) << "Merge Data And Start Syncing."; |
| + |
| + std::string package_name; |
|
Luis Héctor Chávez
2016/07/25 17:31:17
nit: remove
lgcheng
2016/07/25 20:45:17
Done.
|
| + 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)); |
| + package_name = sync_item->package_name; |
|
Luis Héctor Chávez
2016/07/25 17:31:17
nit: const std::string& package_name?
lgcheng
2016/07/25 20:45:17
Done.
|
| + 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 (auto local_package_name : local_packages) { |
|
Luis Héctor Chávez
2016/07/25 17:31:17
can this be const auto&?
lgcheng
2016/07/25 20:45:17
Done.
|
| + 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 (auto iter = sync_items_.begin(); iter != sync_items_.end(); ++iter) { |
|
Luis Héctor Chávez
2016/07/25 17:31:17
nit: can this be for (const auto& item : sync_item
lgcheng
2016/07/25 20:45:17
Done.
|
| + list.emplace_back(GetSyncDataFromSyncItem(iter->second.get())); |
| + } |
| + |
| + for (auto iter = pending_install_items_.begin(); |
| + iter != pending_install_items_.end(); ++iter) { |
| + list.emplace_back(GetSyncDataFromSyncItem(iter->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 (auto iter = change_list.begin(); iter != change_list.end(); ++iter) { |
| + const SyncChange& change = *iter; |
| + |
| + 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 != sync_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 |