sync_engine.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync_file_system/drive_backend/sync_engine.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/threading/sequenced_worker_pool.h"
11#include "base/values.h"
12#include "chrome/browser/drive/drive_api_service.h"
13#include "chrome/browser/drive/drive_notification_manager.h"
14#include "chrome/browser/drive/drive_notification_manager_factory.h"
15#include "chrome/browser/drive/drive_service_interface.h"
16#include "chrome/browser/drive/drive_uploader.h"
17#include "chrome/browser/extensions/extension_service.h"
18#include "chrome/browser/profiles/profile.h"
19#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20#include "chrome/browser/signin/signin_manager_factory.h"
21#include "chrome/browser/sync_file_system/drive_backend/conflict_resolver.h"
22#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
23#include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
24#include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h"
25#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
26#include "chrome/browser/sync_file_system/drive_backend/register_app_task.h"
27#include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h"
28#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
29#include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
30#include "chrome/browser/sync_file_system/drive_backend/sync_task.h"
31#include "chrome/browser/sync_file_system/drive_backend/sync_worker.h"
32#include "chrome/browser/sync_file_system/drive_backend/uninstall_app_task.h"
33#include "chrome/browser/sync_file_system/file_status_observer.h"
34#include "chrome/browser/sync_file_system/logger.h"
35#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
36#include "components/signin/core/browser/profile_oauth2_token_service.h"
37#include "components/signin/core/browser/signin_manager.h"
38#include "content/public/browser/browser_thread.h"
39#include "extensions/browser/extension_system.h"
40#include "extensions/browser/extension_system_provider.h"
41#include "extensions/browser/extensions_browser_client.h"
42#include "extensions/common/extension.h"
43#include "google_apis/drive/drive_api_url_generator.h"
44#include "google_apis/drive/gdata_wapi_url_generator.h"
45#include "webkit/common/blob/scoped_file.h"
46#include "webkit/common/fileapi/file_system_util.h"
47
48namespace sync_file_system {
49
50class RemoteChangeProcessor;
51
52namespace drive_backend {
53namespace {
54
55void EmptyStatusCallback(SyncStatusCode status) {}
56
57}  // namespace
58
59scoped_ptr<SyncEngine> SyncEngine::CreateForBrowserContext(
60    content::BrowserContext* context) {
61  scoped_refptr<base::SequencedWorkerPool> worker_pool(
62      content::BrowserThread::GetBlockingPool());
63  scoped_refptr<base::SequencedTaskRunner> drive_task_runner(
64      worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
65          worker_pool->GetSequenceToken(),
66          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
67
68  Profile* profile = Profile::FromBrowserContext(context);
69  ProfileOAuth2TokenService* token_service =
70      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
71  scoped_ptr<drive::DriveServiceInterface> drive_service(
72      new drive::DriveAPIService(
73          token_service,
74          context->GetRequestContext(),
75          drive_task_runner.get(),
76          GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction),
77          GURL(google_apis::DriveApiUrlGenerator::
78               kBaseDownloadUrlForProduction),
79          GURL(google_apis::GDataWapiUrlGenerator::kBaseUrlForProduction),
80          std::string() /* custom_user_agent */));
81  SigninManagerBase* signin_manager =
82      SigninManagerFactory::GetForProfile(profile);
83  drive_service->Initialize(signin_manager->GetAuthenticatedAccountId());
84
85  scoped_ptr<drive::DriveUploaderInterface> drive_uploader(
86      new drive::DriveUploader(drive_service.get(), drive_task_runner.get()));
87
88  drive::DriveNotificationManager* notification_manager =
89      drive::DriveNotificationManagerFactory::GetForBrowserContext(context);
90  ExtensionService* extension_service =
91      extensions::ExtensionSystem::Get(context)->extension_service();
92
93  scoped_refptr<base::SequencedTaskRunner> task_runner(
94      worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
95          worker_pool->GetSequenceToken(),
96          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
97
98  scoped_ptr<drive_backend::SyncEngine> sync_engine(
99      new SyncEngine(drive_service.Pass(),
100                     drive_uploader.Pass(),
101                     notification_manager,
102                     extension_service,
103                     signin_manager));
104  sync_engine->Initialize(GetSyncFileSystemDir(context->GetPath()),
105                          task_runner.get(),
106                          NULL);
107
108  return sync_engine.Pass();
109}
110
111void SyncEngine::AppendDependsOnFactories(
112    std::set<BrowserContextKeyedServiceFactory*>* factories) {
113  DCHECK(factories);
114  factories->insert(drive::DriveNotificationManagerFactory::GetInstance());
115  factories->insert(SigninManagerFactory::GetInstance());
116  factories->insert(
117      extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
118}
119
120SyncEngine::~SyncEngine() {
121  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
122  GetDriveService()->RemoveObserver(this);
123  if (notification_manager_)
124    notification_manager_->RemoveObserver(this);
125}
126
127void SyncEngine::Initialize(const base::FilePath& base_dir,
128                            base::SequencedTaskRunner* task_runner,
129                            leveldb::Env* env_override) {
130  scoped_ptr<SyncEngineContext> sync_engine_context(
131      new SyncEngineContext(drive_service_.get(),
132                            drive_uploader_.get(),
133                            task_runner));
134  // TODO(peria): Move this create function to thread pool.
135  sync_worker_ = SyncWorker::CreateOnWorker(weak_ptr_factory_.GetWeakPtr(),
136                                            base_dir,
137                                            sync_engine_context.Pass(),
138                                            env_override);
139
140  if (notification_manager_)
141    notification_manager_->AddObserver(this);
142  GetDriveService()->AddObserver(this);
143  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
144}
145
146void SyncEngine::AddServiceObserver(SyncServiceObserver* observer) {
147  service_observers_.AddObserver(observer);
148}
149
150void SyncEngine::AddFileStatusObserver(FileStatusObserver* observer) {
151  file_status_observers_.AddObserver(observer);
152}
153
154void SyncEngine::RegisterOrigin(
155    const GURL& origin, const SyncStatusCallback& callback) {
156  sync_worker_->RegisterOrigin(origin, callback);
157}
158
159void SyncEngine::EnableOrigin(
160    const GURL& origin, const SyncStatusCallback& callback) {
161  sync_worker_->EnableOrigin(origin, callback);
162}
163
164void SyncEngine::DisableOrigin(
165    const GURL& origin, const SyncStatusCallback& callback) {
166  sync_worker_->DisableOrigin(origin, callback);
167}
168
169void SyncEngine::UninstallOrigin(
170    const GURL& origin,
171    UninstallFlag flag,
172    const SyncStatusCallback& callback) {
173  sync_worker_->UninstallOrigin(origin, flag, callback);
174}
175
176void SyncEngine::ProcessRemoteChange(const SyncFileCallback& callback) {
177  sync_worker_->ProcessRemoteChange(callback);
178}
179
180void SyncEngine::SetRemoteChangeProcessor(
181    RemoteChangeProcessor* processor) {
182  sync_worker_->SetRemoteChangeProcessor(processor);
183}
184
185LocalChangeProcessor* SyncEngine::GetLocalChangeProcessor() {
186  return this;
187}
188
189bool SyncEngine::IsConflicting(const fileapi::FileSystemURL& url) {
190  // TODO(tzik): Implement this before we support manual conflict resolution.
191  return false;
192}
193
194RemoteServiceState SyncEngine::GetCurrentState() const {
195  return sync_worker_->GetCurrentState();
196}
197
198void SyncEngine::GetOriginStatusMap(OriginStatusMap* status_map) {
199  sync_worker_->GetOriginStatusMap(status_map);
200}
201
202scoped_ptr<base::ListValue> SyncEngine::DumpFiles(const GURL& origin) {
203  return sync_worker_->DumpFiles(origin);
204}
205
206scoped_ptr<base::ListValue> SyncEngine::DumpDatabase() {
207  return sync_worker_->DumpDatabase();
208}
209
210void SyncEngine::SetSyncEnabled(bool enabled) {
211  sync_worker_->SetSyncEnabled(enabled);
212}
213
214void SyncEngine::UpdateSyncEnabled(bool enabled) {
215  const char* status_message = enabled ? "Sync is enabled" : "Sync is disabled";
216  FOR_EACH_OBSERVER(
217      Observer, service_observers_,
218      OnRemoteServiceStateUpdated(GetCurrentState(), status_message));
219}
220
221SyncStatusCode SyncEngine::SetDefaultConflictResolutionPolicy(
222    ConflictResolutionPolicy policy) {
223  return sync_worker_->SetDefaultConflictResolutionPolicy(policy);
224}
225
226SyncStatusCode SyncEngine::SetConflictResolutionPolicy(
227    const GURL& origin,
228    ConflictResolutionPolicy policy) {
229  return sync_worker_->SetConflictResolutionPolicy(origin, policy);
230}
231
232ConflictResolutionPolicy SyncEngine::GetDefaultConflictResolutionPolicy()
233    const {
234  return sync_worker_->GetDefaultConflictResolutionPolicy();
235}
236
237ConflictResolutionPolicy SyncEngine::GetConflictResolutionPolicy(
238    const GURL& origin) const {
239  return sync_worker_->GetConflictResolutionPolicy(origin);
240}
241
242void SyncEngine::GetRemoteVersions(
243    const fileapi::FileSystemURL& url,
244    const RemoteVersionsCallback& callback) {
245  // TODO(tzik): Implement this before we support manual conflict resolution.
246  callback.Run(SYNC_STATUS_FAILED, std::vector<Version>());
247}
248
249void SyncEngine::DownloadRemoteVersion(
250    const fileapi::FileSystemURL& url,
251    const std::string& version_id,
252    const DownloadVersionCallback& callback) {
253  // TODO(tzik): Implement this before we support manual conflict resolution.
254  callback.Run(SYNC_STATUS_FAILED, webkit_blob::ScopedFile());
255}
256
257void SyncEngine::PromoteDemotedChanges() {
258  MetadataDatabase* metadata_db = GetMetadataDatabase();
259  if (metadata_db && metadata_db->HasLowPriorityDirtyTracker()) {
260    metadata_db->PromoteLowerPriorityTrackersToNormal();
261    FOR_EACH_OBSERVER(
262        Observer,
263        service_observers_,
264        OnRemoteChangeQueueUpdated(metadata_db->CountDirtyTracker()));
265  }
266}
267
268void SyncEngine::ApplyLocalChange(
269    const FileChange& local_change,
270    const base::FilePath& local_path,
271    const SyncFileMetadata& local_metadata,
272    const fileapi::FileSystemURL& url,
273    const SyncStatusCallback& callback) {
274  sync_worker_->ApplyLocalChange(
275      local_change, local_path, local_metadata, url, callback);
276}
277
278SyncTaskManager* SyncEngine::GetSyncTaskManagerForTesting() {
279  return sync_worker_->GetSyncTaskManager();
280}
281
282void SyncEngine::OnNotificationReceived() {
283  sync_worker_->OnNotificationReceived();
284}
285
286void SyncEngine::OnPushNotificationEnabled(bool) {}
287
288void SyncEngine::OnReadyToSendRequests() {
289  sync_worker_->OnReadyToSendRequests(
290      signin_manager_ ? signin_manager_->GetAuthenticatedAccountId() : "");
291}
292
293void SyncEngine::OnRefreshTokenInvalid() {
294  sync_worker_->OnRefreshTokenInvalid();
295}
296
297void SyncEngine::OnNetworkChanged(
298    net::NetworkChangeNotifier::ConnectionType type) {
299  sync_worker_->OnNetworkChanged(type);
300}
301
302drive::DriveServiceInterface* SyncEngine::GetDriveService() {
303  return sync_worker_->GetDriveService();
304}
305
306drive::DriveUploaderInterface* SyncEngine::GetDriveUploader() {
307  return sync_worker_->GetDriveUploader();
308}
309
310MetadataDatabase* SyncEngine::GetMetadataDatabase() {
311  return sync_worker_->GetMetadataDatabase();
312}
313
314SyncEngine::SyncEngine(
315    scoped_ptr<drive::DriveServiceInterface> drive_service,
316    scoped_ptr<drive::DriveUploaderInterface> drive_uploader,
317    drive::DriveNotificationManager* notification_manager,
318    ExtensionServiceInterface* extension_service,
319    SigninManagerBase* signin_manager)
320    : drive_service_(drive_service.Pass()),
321      drive_uploader_(drive_uploader.Pass()),
322      notification_manager_(notification_manager),
323      extension_service_(extension_service),
324      signin_manager_(signin_manager),
325      weak_ptr_factory_(this) {}
326
327void SyncEngine::DidProcessRemoteChange(RemoteToLocalSyncer* syncer) {
328  if (syncer->sync_action() != SYNC_ACTION_NONE && syncer->url().is_valid()) {
329    FOR_EACH_OBSERVER(FileStatusObserver,
330                      file_status_observers_,
331                      OnFileStatusChanged(syncer->url(),
332                                          SYNC_FILE_STATUS_SYNCED,
333                                          syncer->sync_action(),
334                                          SYNC_DIRECTION_REMOTE_TO_LOCAL));
335  }
336}
337
338void SyncEngine::DidApplyLocalChange(LocalToRemoteSyncer* syncer,
339                                     SyncStatusCode status) {
340  if ((status == SYNC_STATUS_OK || status == SYNC_STATUS_RETRY) &&
341      syncer->url().is_valid() &&
342      syncer->sync_action() != SYNC_ACTION_NONE) {
343    fileapi::FileSystemURL updated_url = syncer->url();
344    if (!syncer->target_path().empty()) {
345      updated_url = CreateSyncableFileSystemURL(syncer->url().origin(),
346                                                syncer->target_path());
347    }
348    FOR_EACH_OBSERVER(FileStatusObserver,
349                      file_status_observers_,
350                      OnFileStatusChanged(updated_url,
351                                          SYNC_FILE_STATUS_SYNCED,
352                                          syncer->sync_action(),
353                                          SYNC_DIRECTION_LOCAL_TO_REMOTE));
354  }
355}
356
357void SyncEngine::UpdateServiceState(const std::string& description) {
358  FOR_EACH_OBSERVER(
359      Observer, service_observers_,
360      OnRemoteServiceStateUpdated(GetCurrentState(), description));
361}
362
363void SyncEngine::UpdateRegisteredApps() {
364  if (!extension_service_)
365    return;
366
367  MetadataDatabase* metadata_db = GetMetadataDatabase();
368  DCHECK(metadata_db);
369  std::vector<std::string> app_ids;
370  metadata_db->GetRegisteredAppIDs(&app_ids);
371
372  // Update the status of every origin using status from ExtensionService.
373  for (std::vector<std::string>::const_iterator itr = app_ids.begin();
374       itr != app_ids.end(); ++itr) {
375    const std::string& app_id = *itr;
376    GURL origin =
377        extensions::Extension::GetBaseURLFromExtensionId(app_id);
378    if (!extension_service_->GetInstalledExtension(app_id)) {
379      // Extension has been uninstalled.
380      // (At this stage we can't know if it was unpacked extension or not,
381      // so just purge the remote folder.)
382      UninstallOrigin(origin,
383                      RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE,
384                      base::Bind(&EmptyStatusCallback));
385      continue;
386    }
387    FileTracker tracker;
388    if (!metadata_db->FindAppRootTracker(app_id, &tracker)) {
389      // App will register itself on first run.
390      continue;
391    }
392    bool is_app_enabled = extension_service_->IsExtensionEnabled(app_id);
393    bool is_app_root_tracker_enabled =
394        tracker.tracker_kind() == TRACKER_KIND_APP_ROOT;
395    if (is_app_enabled && !is_app_root_tracker_enabled)
396      EnableOrigin(origin, base::Bind(&EmptyStatusCallback));
397    else if (!is_app_enabled && is_app_root_tracker_enabled)
398      DisableOrigin(origin, base::Bind(&EmptyStatusCallback));
399  }
400}
401
402void SyncEngine::NotifyLastOperationStatus() {
403  FOR_EACH_OBSERVER(
404      Observer,
405      service_observers_,
406      OnRemoteChangeQueueUpdated(
407          GetMetadataDatabase()->CountDirtyTracker()));
408}
409
410}  // namespace drive_backend
411}  // namespace sync_file_system
412