summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync_file_system/drive_file_sync_service.h
blob: 74b50642b7e77b028baf611cb55ecde55975c767 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
// Copyright (c) 2012 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_SYNC_FILE_SYSTEM_DRIVE_FILE_SYNC_SERVICE_H_
#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_FILE_SYNC_SERVICE_H_

#include <deque>
#include <map>
#include <set>
#include <string>
#include <vector>

#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/non_thread_safe.h"
#include "chrome/browser/google_apis/drive_notification_observer.h"
#include "chrome/browser/sync_file_system/drive/api_util_interface.h"
#include "chrome/browser/sync_file_system/drive_metadata_store.h"
#include "chrome/browser/sync_file_system/local_change_processor.h"
#include "chrome/browser/sync_file_system/local_sync_operation_resolver.h"
#include "chrome/browser/sync_file_system/remote_change_handler.h"
#include "chrome/browser/sync_file_system/remote_file_sync_service.h"
#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
#include "webkit/browser/fileapi/syncable/file_change.h"
#include "webkit/browser/fileapi/syncable/sync_action.h"
#include "webkit/browser/fileapi/syncable/sync_callbacks.h"
#include "webkit/browser/fileapi/syncable/sync_direction.h"
#include "webkit/browser/fileapi/syncable/sync_status_code.h"

class ExtensionService;

namespace google_apis {
class ResourceList;
}

namespace tracked_objects {
class Location;
}

namespace sync_file_system {

namespace drive {
class LocalChangeProcessorDelegate;
}

class DriveFileSyncTaskManager;

// Maintains remote file changes.
// Owned by SyncFileSystemService (which is a per-profile object).
class DriveFileSyncService : public RemoteFileSyncService,
                             public LocalChangeProcessor,
                             public drive::APIUtilObserver,
                             public base::NonThreadSafe,
                             public base::SupportsWeakPtr<DriveFileSyncService>,
                             public google_apis::DriveNotificationObserver {
 public:
  enum ConflictResolutionResult {
    CONFLICT_RESOLUTION_MARK_CONFLICT,
    CONFLICT_RESOLUTION_LOCAL_WIN,
    CONFLICT_RESOLUTION_REMOTE_WIN,
  };

  typedef base::Callback<void(const SyncStatusCallback& callback)> Task;

  static const char kServiceName[];
  static ConflictResolutionPolicy kDefaultPolicy;

  virtual ~DriveFileSyncService();

  // Creates DriveFileSyncService.
  static scoped_ptr<DriveFileSyncService> Create(Profile* profile);

  // Creates DriveFileSyncService instance for testing.
  // |metadata_store| must be initialized beforehand.
  static scoped_ptr<DriveFileSyncService> CreateForTesting(
      Profile* profile,
      const base::FilePath& base_dir,
      scoped_ptr<drive::APIUtilInterface> api_util,
      scoped_ptr<DriveMetadataStore> metadata_store);

  // Destroys |sync_service| and passes the ownership of |sync_client| to caller
  // for testing.
  static scoped_ptr<drive::APIUtilInterface> DestroyAndPassAPIUtilForTesting(
      scoped_ptr<DriveFileSyncService> sync_service);

  // RemoteFileSyncService overrides.
  virtual void AddServiceObserver(Observer* observer) OVERRIDE;
  virtual void AddFileStatusObserver(FileStatusObserver* observer) OVERRIDE;
  virtual void RegisterOriginForTrackingChanges(
      const GURL& origin,
      const SyncStatusCallback& callback) OVERRIDE;
  virtual void UnregisterOriginForTrackingChanges(
      const GURL& origin,
      const SyncStatusCallback& callback) OVERRIDE;
  virtual void EnableOriginForTrackingChanges(
      const GURL& origin,
      const SyncStatusCallback& callback) OVERRIDE;
  virtual void DisableOriginForTrackingChanges(
      const GURL& origin,
      const SyncStatusCallback& callback) OVERRIDE;
  virtual void UninstallOrigin(
      const GURL& origin,
      const SyncStatusCallback& callback) OVERRIDE;
  virtual void ProcessRemoteChange(const SyncFileCallback& callback) OVERRIDE;
  virtual void SetRemoteChangeProcessor(
      RemoteChangeProcessor* processor) OVERRIDE;
  virtual LocalChangeProcessor* GetLocalChangeProcessor() OVERRIDE;
  virtual bool IsConflicting(const fileapi::FileSystemURL& url) OVERRIDE;
  virtual RemoteServiceState GetCurrentState() const OVERRIDE;
  virtual const char* GetServiceName() const OVERRIDE;
  virtual void SetSyncEnabled(bool enabled) OVERRIDE;
  virtual SyncStatusCode SetConflictResolutionPolicy(
      ConflictResolutionPolicy resolution) OVERRIDE;
  virtual ConflictResolutionPolicy GetConflictResolutionPolicy() const OVERRIDE;

  // LocalChangeProcessor overrides.
  virtual void ApplyLocalChange(
      const FileChange& change,
      const base::FilePath& local_file_path,
      const SyncFileMetadata& local_file_metadata,
      const fileapi::FileSystemURL& url,
      const SyncStatusCallback& callback) OVERRIDE;

  // DriveFileSyncClientObserver overrides.
  virtual void OnAuthenticated() OVERRIDE;
  virtual void OnNetworkConnected() OVERRIDE;

  // google_apis::DriveNotificationObserver implementation.
  virtual void OnNotificationReceived() OVERRIDE;
  virtual void OnPushNotificationEnabled(bool enabled) OVERRIDE;

  // Called from DriveFileSyncTaskManager.
  // TODO: factor out as an interface.
  void MaybeScheduleNextTask();
  void NotifyLastOperationStatus(
      SyncStatusCode sync_status,
      google_apis::GDataErrorCode gdata_error);

  static std::string PathToTitle(const base::FilePath& path);
  static base::FilePath TitleToPath(const std::string& title);
  static DriveMetadata::ResourceType SyncFileTypeToDriveMetadataResourceType(
      SyncFileType file_type);

 private:
  friend class DriveFileSyncTaskManager;
  friend class drive::LocalChangeProcessorDelegate;

  friend class DriveFileSyncServiceMockTest;
  friend class DriveFileSyncServiceSyncTest;
  struct ApplyLocalChangeParam;
  struct ProcessRemoteChangeParam;

  typedef base::Callback<void(const base::Time& time,
                              SyncFileType remote_file_type,
                              SyncStatusCode status)> UpdatedTimeCallback;
  typedef base::Callback<
      void(SyncStatusCode status,
           const std::string& resource_id)> ResourceIdCallback;

  explicit DriveFileSyncService(Profile* profile);

  void Initialize(scoped_ptr<DriveFileSyncTaskManager> task_manager,
                  const SyncStatusCallback& callback);
  void InitializeForTesting(scoped_ptr<DriveFileSyncTaskManager> task_manager,
                            const base::FilePath& base_dir,
                            scoped_ptr<drive::APIUtilInterface> sync_client,
                            scoped_ptr<DriveMetadataStore> metadata_store,
                            const SyncStatusCallback& callback);

  void DidInitializeMetadataStore(const SyncStatusCallback& callback,
                                  SyncStatusCode status,
                                  bool created);
  void DidGetDriveRootResourceId(const SyncStatusCallback& callback,
                                 google_apis::GDataErrorCode error,
                                 const std::string& root_resource_id);

  void UpdateServiceStateFromLastOperationStatus(
      SyncStatusCode sync_status,
      google_apis::GDataErrorCode gdata_error);

  // Updates the service state. Also this may notify observers if the
  // service state has been changed from the original value.
  void UpdateServiceState(RemoteServiceState state,
                          const std::string& description);

  void DoRegisterOriginForTrackingChanges(
      const GURL& origin,
      const SyncStatusCallback& callback);
  void DoUnregisterOriginForTrackingChanges(
      const GURL& origin,
      const SyncStatusCallback& callback);
  void DoEnableOriginForTrackingChanges(
      const GURL& origin,
      const SyncStatusCallback& callback);
  void DoDisableOriginForTrackingChanges(
      const GURL& origin,
      const SyncStatusCallback& callback);
  void DoUninstallOrigin(
      const GURL& origin,
      const SyncStatusCallback& callback);
  void DoProcessRemoteChange(
      const SyncFileCallback& sync_callback,
      const SyncStatusCallback& completion_callback);
  void DoApplyLocalChange(
      const FileChange& change,
      const base::FilePath& local_file_path,
      const SyncFileMetadata& local_file_metadata,
      const fileapi::FileSystemURL& url,
      const SyncStatusCallback& callback);

  // Local synchronization related methods.
  ConflictResolutionResult ResolveConflictForLocalSync(
      SyncFileType local_file_type,
      const base::Time& local_update_time,
      SyncFileType remote_file_type,
      const base::Time& remote_update_time);
  void DidApplyLocalChange(const SyncStatusCallback& callback,
                           SyncStatusCode status);

  void UpdateRegisteredOrigins();

  void StartBatchSync(const SyncStatusCallback& callback);
  void GetDriveDirectoryForOrigin(const GURL& origin,
                                  const SyncStatusCallback& callback,
                                  const std::string& sync_root_resource_id);
  void DidGetDriveDirectoryForOrigin(const GURL& origin,
                                     const SyncStatusCallback& callback,
                                     SyncStatusCode status,
                                     const std::string& resource_id);
  void DidUninstallOrigin(const GURL& origin,
                          const SyncStatusCallback& callback,
                          google_apis::GDataErrorCode error);
  void DidGetLargestChangeStampForBatchSync(
      const SyncStatusCallback& callback,
      const GURL& origin,
      const std::string& resource_id,
      google_apis::GDataErrorCode error,
      int64 largest_changestamp);
  void DidGetDirectoryContentForBatchSync(
      const SyncStatusCallback& callback,
      const GURL& origin,
      const std::string& resource_id,
      int64 largest_changestamp,
      google_apis::GDataErrorCode error,
      scoped_ptr<google_apis::ResourceList> feed);

  // Remote synchronization related methods.
  void DidPrepareForProcessRemoteChange(
      scoped_ptr<ProcessRemoteChangeParam> param,
      SyncStatusCode status,
      const SyncFileMetadata& metadata,
      const FileChangeList& changes);
  void DidResolveConflictToLocalChange(
      scoped_ptr<ProcessRemoteChangeParam> param,
      SyncStatusCode status);
  void DownloadForRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param);
  void DidGetTemporaryFileForDownload(
      scoped_ptr<ProcessRemoteChangeParam> param,
      bool success);
  void DidDownloadFileForRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param,
      google_apis::GDataErrorCode error,
      const std::string& md5_checksum,
      int64 file_size,
      const base::Time& updated_time);
  void DidApplyRemoteChange(
      scoped_ptr<ProcessRemoteChangeParam> param,
      SyncStatusCode status);
  void DidCleanUpForRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param,
      bool success);
  void DeleteMetadataForRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param);
  void CompleteRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param,
      SyncStatusCode status);
  void AbortRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param,
      SyncStatusCode status);
  void FinalizeRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param,
      SyncStatusCode status);
  void HandleConflictForRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param,
      const base::Time& remote_updated_time,
      SyncFileType remote_file_change,
      SyncStatusCode status);
  void ResolveConflictToLocalForRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param);
  void StartOverRemoteSync(
      scoped_ptr<ProcessRemoteChangeParam> param,
      SyncStatusCode status);

  // Returns true if |pending_changes_| was updated.
  bool AppendRemoteChange(
      const GURL& origin,
      const google_apis::ResourceEntry& entry,
      int64 changestamp,
      RemoteChangeHandler::RemoteSyncType sync_type);
  bool AppendFetchChange(
      const GURL& origin,
      const base::FilePath& path,
      const std::string& resource_id,
      SyncFileType file_type);
  bool AppendRemoteChangeInternal(
      const GURL& origin,
      const base::FilePath& path,
      bool is_deleted,
      const std::string& resource_id,
      int64 changestamp,
      const std::string& remote_file_md5,
      const base::Time& updated_time,
      SyncFileType file_type,
      RemoteChangeHandler::RemoteSyncType sync_type);
  void RemoveRemoteChange(const fileapi::FileSystemURL& url);
  void MaybeMarkAsIncrementalSyncOrigin(const GURL& origin);

  void MarkConflict(
      const fileapi::FileSystemURL& url,
      DriveMetadata* drive_metadata,
      const SyncStatusCallback& callback);
  void DidGetRemoteFileMetadataForRemoteUpdatedTime(
      const UpdatedTimeCallback& callback,
      google_apis::GDataErrorCode error,
      scoped_ptr<google_apis::ResourceEntry> entry);

  // A wrapper implementation to GDataErrorCodeToSyncStatusCode which returns
  // authentication error if the user is not signed in.
  SyncStatusCode GDataErrorCodeToSyncStatusCodeWrapper(
      google_apis::GDataErrorCode error);

  base::FilePath temporary_file_dir_;

  // May start batch sync or incremental sync.
  // This posts either one of following tasks:
  // - StartBatchSyncForOrigin() if it has any pending batch sync origins, or
  // - FetchChangesForIncrementalSync() otherwise.
  //
  // These two methods are called only from this method.
  void MaybeStartFetchChanges();

  void FetchChangesForIncrementalSync(const SyncStatusCallback& callback);
  void DidFetchChangesForIncrementalSync(
      const SyncStatusCallback& callback,
      bool has_new_changes,
      google_apis::GDataErrorCode error,
      scoped_ptr<google_apis::ResourceList> changes);
  bool GetOriginForEntry(const google_apis::ResourceEntry& entry, GURL* origin);
  void NotifyObserversFileStatusChanged(const fileapi::FileSystemURL& url,
                                        SyncFileStatus sync_status,
                                        SyncAction action_taken,
                                        SyncDirection direction);

  void HandleSyncRootDirectoryChange(const google_apis::ResourceEntry& entry);
  void HandleOriginRootDirectoryChange(const google_apis::ResourceEntry& entry);

  void EnsureSyncRootDirectory(const ResourceIdCallback& callback);
  void DidEnsureSyncRoot(const ResourceIdCallback& callback,
                         google_apis::GDataErrorCode error,
                         const std::string& sync_root_resource_id);
  void EnsureOriginRootDirectory(const GURL& origin,
                                 const ResourceIdCallback& callback);
  void DidEnsureSyncRootForOriginRoot(const GURL& origin,
                                      const ResourceIdCallback& callback,
                                      SyncStatusCode status,
                                      const std::string& sync_root_resource_id);
  void DidEnsureOriginRoot(const GURL& origin,
                           const ResourceIdCallback& callback,
                           google_apis::GDataErrorCode error,
                           const std::string& resource_id);

  // This function returns Resouce ID for the sync root directory if available.
  // Returns an empty string 1) when the resource ID has not been initialized
  // yet, and 2) after the service has detected the remote sync root folder was
  // removed.
  std::string sync_root_resource_id();

  scoped_ptr<DriveMetadataStore> metadata_store_;
  scoped_ptr<drive::APIUtilInterface> api_util_;

  Profile* profile_;

  scoped_ptr<DriveFileSyncTaskManager> task_manager_;

  scoped_ptr<drive::LocalChangeProcessorDelegate> running_local_sync_task_;

  // The current remote service state. This does NOT reflect the
  // sync_enabled_ flag, while GetCurrentState() DOES reflect the flag
  // value (i.e. it returns REMOTE_SERVICE_DISABLED when sync_enabled_
  // is false even if state_ is REMOTE_SERVICE_OK).
  RemoteServiceState state_;

  // Indicates if sync is enabled or not. This flag can be turned on or
  // off by SetSyncEnabled() method.  To start synchronization
  // this needs to be true and state_ needs to be REMOTE_SERVICE_OK.
  bool sync_enabled_;

  int64 largest_fetched_changestamp_;

  std::map<GURL, std::string> pending_batch_sync_origins_;

  // Is set to true when there's a fair possibility that we have some
  // remote changes that haven't been fetched yet.
  //
  // This flag is set when:
  // - This gets invalidation notification,
  // - The service is authenticated or becomes online, and
  // - The polling timer is fired.
  //
  // This flag is cleared when:
  // - A batch or incremental sync has been started, and
  // - When all pending batch sync tasks have been finished.
  bool may_have_unfetched_changes_;

  ObserverList<Observer> service_observers_;
  ObserverList<FileStatusObserver> file_status_observers_;

  RemoteChangeHandler remote_change_handler_;
  RemoteChangeProcessor* remote_change_processor_;

  ConflictResolutionPolicy conflict_resolution_;

  DISALLOW_COPY_AND_ASSIGN(DriveFileSyncService);
};

}  // namespace sync_file_system

#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_FILE_SYNC_SERVICE_H_