sync_file_system_service.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync_file_system/sync_file_system_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/format_macros.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/extensions/extension_prefs.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_factory.h"
2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h"
222385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/sync_file_system/logger.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/sync_file_system/sync_direction.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/sync_file_system/sync_event_observer.h"
262385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/sync_file_metadata.h"
272385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/sync_status_code.h"
282385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension.h"
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_details.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_service.h"
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "content/public/browser/storage_partition.h"
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "extensions/common/manifest_constants.h"
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/browser/fileapi/file_system_context.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using extensions::Extension;
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using extensions::ExtensionPrefs;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using fileapi::FileSystemURL;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using fileapi::FileSystemURLSet;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sync_file_system {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Default delay when more changes are available.
5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int64 kSyncDelayInMilliseconds = 1 * base::Time::kMillisecondsPerSecond;
5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Default delay when there're more than 10 pending changes.
5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int64 kSyncDelayFastInMilliseconds = 100;
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kPendingChangeThresholdForFastSync = 10;
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Default delay when remote service is temporarily unavailable.
5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int64 kSyncDelaySlowInMilliseconds =
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    30 * base::Time::kMillisecondsPerSecond;  // Start with 30 sec + exp backoff
5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Default delay when there're no changes.
6168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int64 kSyncDelayMaxInMilliseconds =
6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    30 * 60 * base::Time::kMillisecondsPerSecond;  // 30 min
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SyncServiceState RemoteStateToSyncServiceState(
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RemoteServiceState state) {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (state) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case REMOTE_SERVICE_OK:
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return SYNC_SERVICE_RUNNING;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return SYNC_SERVICE_TEMPORARY_UNAVAILABLE;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return SYNC_SERVICE_AUTHENTICATION_REQUIRED;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case REMOTE_SERVICE_DISABLED:
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return SYNC_SERVICE_DISABLED;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  NOTREACHED() << "Unknown remote service state: " << state;
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return SYNC_SERVICE_DISABLED;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DidHandleOriginForExtensionUnloadedEvent(
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int type,
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& origin,
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncStatusCode code) {
84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED == type ||
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)         chrome::NOTIFICATION_EXTENSION_UNINSTALLED == type);
86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (code != SYNC_STATUS_OK &&
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      code != SYNC_STATUS_UNKNOWN_ORIGIN) {
88a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    switch (type) {
89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      case chrome::NOTIFICATION_EXTENSION_UNLOADED:
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        util::Log(logging::LOG_WARNING,
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  FROM_HERE,
92a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                  "Disabling origin for UNLOADED(DISABLE) failed: %s",
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  origin.spec().c_str());
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        util::Log(logging::LOG_WARNING,
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  FROM_HERE,
98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                  "Uninstall origin for UNINSTALLED failed: %s",
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  origin.spec().c_str());
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DidHandleOriginForExtensionEnabledEvent(
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int type,
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& origin,
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncStatusCode code) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED == type);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (code != SYNC_STATUS_OK)
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    util::Log(logging::LOG_WARNING,
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              FROM_HERE,
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              "Enabling origin for ENABLED failed: %s",
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              origin.spec().c_str());
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstd::string SyncFileStatusToString(SyncFileStatus sync_file_status) {
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return extensions::api::sync_file_system::ToString(
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      extensions::SyncFileStatusToExtensionEnum(sync_file_status));
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Gets called repeatedly until every SyncFileStatus has been mapped.
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DidGetFileSyncStatusForDump(
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::ListValue* files,
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    size_t* num_results,
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const SyncFileSystemService::DumpFilesCallback& callback,
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::DictionaryValue* file,
1307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    SyncStatusCode sync_status_code,
1317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    SyncFileStatus sync_file_status) {
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(files);
1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(num_results);
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (file)
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    file->SetString("status", SyncFileStatusToString(sync_file_status));
1377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Once all results have been received, run the callback to signal end.
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_LE(*num_results, files->GetSize());
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (++*num_results < files->GetSize())
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  callback.Run(files);
1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class SyncFileSystemService::SyncRunner {
149d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public:
150d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  typedef base::Callback<void(const SyncStatusCallback&)> Task;
151d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SyncRunner(const std::string& task_name,
152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)             const Task& sync_task,
153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)             RemoteFileSyncService* remote_service)
154d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    : task_name_(task_name),
155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      sync_task_(sync_task),
156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      remote_service_(remote_service),
157d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      current_delay_(0),
158d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      last_delay_(0),
159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      pending_changes_(0),
160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      running_(false),
161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      factory_(this) {}
162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ~SyncRunner() {}
163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
164d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  void Schedule() {
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    int64 delay = kSyncDelayInMilliseconds;
166d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (pending_changes_ == 0) {
16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ScheduleInternal(kSyncDelayMaxInMilliseconds);
168d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return;
169d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    switch (remote_service_->GetCurrentState()) {
171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      case REMOTE_SERVICE_OK:
17268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        if (pending_changes_ > kPendingChangeThresholdForFastSync)
17368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          delay = kSyncDelayFastInMilliseconds;
17468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        else
17568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          delay = kSyncDelayInMilliseconds;
176d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        break;
177d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
17968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        delay = kSyncDelaySlowInMilliseconds;
18068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        if (last_delay_ >= kSyncDelaySlowInMilliseconds &&
18168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            last_delay_ < kSyncDelayMaxInMilliseconds)
182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          delay = last_delay_ * 2;
183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        break;
184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
186d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      case REMOTE_SERVICE_DISABLED:
18768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        delay = kSyncDelayMaxInMilliseconds;
188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        break;
189d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
190d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    ScheduleInternal(delay);
191d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
192d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
193d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  void ScheduleIfNotRunning() {
194d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!timer_.IsRunning())
195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      Schedule();
196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
197d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
198d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  void OnChangesUpdated(int64 pending_changes) {
199d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DCHECK_GE(pending_changes, 0);
200d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (pending_changes_ != pending_changes) {
201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      util::Log(logging::LOG_VERBOSE, FROM_HERE,
202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                "[%s] pending_changes updated: %" PRId64,
203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                task_name_.c_str(), pending_changes);
204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    pending_changes_ = pending_changes;
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    Schedule();
207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
209d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int64 pending_changes() const { return pending_changes_; }
210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private:
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  void Finished(SyncStatusCode status) {
213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DCHECK(running_);
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    running_ = false;
215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    util::Log(logging::LOG_VERBOSE, FROM_HERE,
216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              "[%s] * Finished (elapsed: %" PRId64 " sec)",
217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              task_name_.c_str(),
218d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              (base::Time::Now() - last_scheduled_).InSeconds());
219d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC ||
220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        status == SYNC_STATUS_FILE_BUSY)
22168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ScheduleInternal(kSyncDelayMaxInMilliseconds);
222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    else
223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      Schedule();
224d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  void Run() {
227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (running_)
228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return;
229d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    running_ = true;
230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    last_scheduled_ = base::Time::Now();
231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    last_delay_ = current_delay_;
232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
233d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    util::Log(logging::LOG_VERBOSE, FROM_HERE,
234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)              "[%s] * Started", task_name_.c_str());
235d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    sync_task_.Run(base::Bind(&SyncRunner::Finished, factory_.GetWeakPtr()));
237d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
238d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
239d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  void ScheduleInternal(int64 delay) {
24068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    base::TimeDelta time_to_next = base::TimeDelta::FromMilliseconds(delay);
241d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
242d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (timer_.IsRunning()) {
243d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (current_delay_ == delay)
244d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        return;
245d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
246d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::TimeDelta elapsed = base::Time::Now() - last_scheduled_;
24768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (elapsed < time_to_next) {
248d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        time_to_next = time_to_next - elapsed;
24968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      } else {
25068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        time_to_next = base::TimeDelta::FromMilliseconds(
25168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            kSyncDelayFastInMilliseconds);
25268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      }
253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      timer_.Stop();
254d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (current_delay_ != delay) {
257d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      util::Log(logging::LOG_VERBOSE, FROM_HERE,
258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                "[%s] Scheduling task in %" PRId64 " secs",
259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                task_name_.c_str(), time_to_next.InSeconds());
260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    current_delay_ = delay;
262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    timer_.Start(FROM_HERE, time_to_next, this, &SyncRunner::Run);
264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string task_name_;
267d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Task sync_task_;
268d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  RemoteFileSyncService* remote_service_;
269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::OneShotTimer<SyncRunner> timer_;
270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::Time last_scheduled_;
271d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int64 current_delay_;
272d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int64 last_delay_;
273d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int64 pending_changes_;
274d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bool running_;
275d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  base::WeakPtrFactory<SyncRunner> factory_;
276d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
277d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SyncRunner);
278d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)};
279d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
280d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)//-----------------------------------------------------------------------------
281d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncFileSystemService::Shutdown() {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_sync_.reset();
286d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  remote_sync_.reset();
287d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_file_service_->Shutdown();
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_file_service_.reset();
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remote_file_service_.reset();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ProfileSyncServiceBase* profile_sync_service =
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ProfileSyncServiceFactory::GetForProfile(profile_);
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (profile_sync_service)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    profile_sync_service->RemoveObserver(this);
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_ = NULL;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncFileSystemService::~SyncFileSystemService() {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!profile_);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncFileSystemService::InitializeForApp(
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fileapi::FileSystemContext* file_system_context,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& app_origin,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncStatusCallback& callback) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(local_file_service_);
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(remote_file_service_);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(app_origin == app_origin.GetOrigin());
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  util::Log(logging::LOG_VERBOSE, FROM_HERE,
3157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "Initializing for App: %s", app_origin.spec().c_str());
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_file_service_->MaybeInitializeFileSystemContext(
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      app_origin, file_system_context,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SyncFileSystemService::DidInitializeFileSystem,
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 AsWeakPtr(), app_origin, callback));
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SyncServiceState SyncFileSystemService::GetSyncServiceState() {
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return RemoteStateToSyncServiceState(remote_file_service_->GetCurrentState());
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void SyncFileSystemService::GetExtensionStatusMap(
328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::map<GURL, std::string>* status_map) {
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(status_map);
330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  remote_file_service_->GetOriginStatusMap(status_map);
331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid SyncFileSystemService::DumpFiles(const GURL& origin,
3347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                      const DumpFilesCallback& callback) {
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!origin.is_empty());
3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  content::StoragePartition* storage_partition =
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      content::BrowserContext::GetStoragePartitionForSite(profile_, origin);
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fileapi::FileSystemContext* file_system_context =
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      storage_partition->GetFileSystemContext();
3417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  local_file_service_->MaybeInitializeFileSystemContext(
3427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      origin, file_system_context,
3437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump,
3447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 AsWeakPtr(), origin, callback));
3457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::GetFileSyncStatus(
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FileSystemURL& url, const SyncFileStatusCallback& callback) {
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(local_file_service_);
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(remote_file_service_);
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // It's possible to get an invalid FileEntry.
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!url.is_valid()) {
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::MessageLoopProxy::current()->PostTask(
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   SYNC_FILE_ERROR_INVALID_URL,
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   SYNC_FILE_STATUS_UNKNOWN));
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (remote_file_service_->IsConflicting(url)) {
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::MessageLoopProxy::current()->PostTask(
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(callback,
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   SYNC_STATUS_OK,
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   SYNC_FILE_STATUS_CONFLICTING));
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  local_file_service_->HasPendingLocalChanges(
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url,
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus,
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 AsWeakPtr(), callback));
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) {
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.AddObserver(observer);
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::RemoveSyncEventObserver(
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncEventObserver* observer) {
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  observers_.RemoveObserver(observer);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ConflictResolutionPolicy
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncFileSystemService::GetConflictResolutionPolicy() const {
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return remote_file_service_->GetConflictResolutionPolicy();
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SyncStatusCode SyncFileSystemService::SetConflictResolutionPolicy(
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ConflictResolutionPolicy policy) {
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return remote_file_service_->SetConflictResolutionPolicy(policy);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncFileSystemService::SyncFileSystemService(Profile* profile)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(profile),
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sync_enabled_(true) {
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncFileSystemService::Initialize(
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<LocalFileSyncService> local_file_service,
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<RemoteFileSyncService> remote_file_service) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(local_file_service);
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(remote_file_service);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(profile_);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_file_service_ = local_file_service.Pass();
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remote_file_service_ = remote_file_service.Pass();
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  local_file_service_->AddChangeObserver(this);
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  local_file_service_->SetLocalChangeProcessor(
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      remote_file_service_->GetLocalChangeProcessor());
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remote_file_service_->AddServiceObserver(this);
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remote_file_service_->AddFileStatusObserver(this);
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remote_file_service_->SetRemoteChangeProcessor(local_file_service_.get());
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
420d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_sync_.reset(new SyncRunner(
421d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      "Local sync",
422d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&SyncFileSystemService::StartLocalSync, AsWeakPtr()),
423d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      remote_file_service_.get()));
424d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  remote_sync_.reset(new SyncRunner(
425d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      "Remote sync",
426d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&SyncFileSystemService::StartRemoteSync, AsWeakPtr()),
427d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      remote_file_service_.get()));
428d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ProfileSyncServiceBase* profile_sync_service =
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ProfileSyncServiceFactory::GetForProfile(profile_);
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (profile_sync_service) {
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UpdateSyncEnabledStatus(profile_sync_service);
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    profile_sync_service->AddObserver(this);
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 content::Source<Profile>(profile_));
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<Profile>(profile_));
440a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
441a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                 content::Source<Profile>(profile_));
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED,
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<Profile>(profile_));
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::DidInitializeFileSystem(
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& app_origin,
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SyncStatusCallback& callback,
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncStatusCode status) {
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "DidInitializeFileSystem: "
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << app_origin.spec() << " " << status;
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status != SYNC_STATUS_OK) {
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(status);
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Local side of initialization for the app is done.
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Continue on initializing the remote side.
46058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  remote_file_service_->RegisterOrigin(
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      app_origin,
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SyncFileSystemService::DidRegisterOrigin,
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 AsWeakPtr(), app_origin, callback));
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::DidRegisterOrigin(
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& app_origin,
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SyncStatusCallback& callback,
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncStatusCode status) {
47058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  util::Log(logging::LOG_VERBOSE, FROM_HERE,
47158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            "DidInitializeForApp (registered the origin): %s: %s",
47258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            app_origin.spec().c_str(),
47358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            SyncStatusCodeToString(status));
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(status);
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid SyncFileSystemService::DidInitializeFileSystemForDump(
4797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const GURL& origin,
4807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const DumpFilesCallback& callback,
4817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SyncStatusCode status) {
4827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!origin.is_empty());
4837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (status != SYNC_STATUS_OK) {
4857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::ListValue empty_result;
4867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    callback.Run(&empty_result);
4877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::ListValue* files = remote_file_service_->DumpFiles(origin).release();
4917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!files->GetSize()) {
4927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    callback.Run(files);
4937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::Callback<void(base::DictionaryValue* file,
4977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      SyncStatusCode sync_status,
4987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      SyncFileStatus sync_file_status)> completion_callback =
4997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&DidGetFileSyncStatusForDump, base::Owned(files),
5007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 base::Owned(new size_t(0)), callback);
5017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // After all metadata loaded, sync status can be added to each entry.
5037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (size_t i = 0; i < files->GetSize(); ++i) {
5047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::DictionaryValue* file = NULL;
5057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    std::string path_string;
5067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!files->GetDictionary(i, &file) ||
5077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        !file->GetString("path", &path_string)) {
5087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      NOTREACHED();
5097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      completion_callback.Run(
5107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
5117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      continue;
5127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
5137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string);
5157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path);
5167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    GetFileSyncStatus(url, base::Bind(completion_callback, file));
5177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
5197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) {
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_enabled_ = enabled;
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remote_file_service_->SetSyncEnabled(sync_enabled_);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void SyncFileSystemService::StartLocalSync(
526d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const SyncStatusCallback& callback) {
527d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_file_service_->ProcessLocalChange(
528d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&SyncFileSystemService::DidProcessLocalChange, AsWeakPtr(),
529d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 callback));
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
532d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void SyncFileSystemService::StartRemoteSync(
533d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const SyncStatusCallback& callback) {
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remote_file_service_->ProcessRemoteChange(
535d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&SyncFileSystemService::DidProcessRemoteChange, AsWeakPtr(),
536d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 callback));
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::DidProcessRemoteChange(
540d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const SyncStatusCallback& callback,
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncStatusCode status,
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FileSystemURL& url) {
5437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  util::Log(logging::LOG_VERBOSE, FROM_HERE,
5447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "ProcessRemoteChange finished with status=%d (%s) for url=%s",
5457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            status, SyncStatusCodeToString(status), url.DebugString().c_str());
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
547d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (url.is_valid())
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_file_service_->ClearSyncFlagForURL(url);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status == SYNC_STATUS_FILE_BUSY) {
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_file_service_->RegisterURLForWaitingSync(
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url, base::Bind(&SyncFileSystemService::OnSyncEnabledForRemoteSync,
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        AsWeakPtr()));
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
556d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  callback.Run(status);
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::DidProcessLocalChange(
560d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const SyncStatusCallback& callback,
561d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    SyncStatusCode status,
562d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const FileSystemURL& url) {
5637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  util::Log(logging::LOG_VERBOSE, FROM_HERE,
5647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "ProcessLocalChange finished with status=%d (%s) for url=%s",
5657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            status, SyncStatusCodeToString(status), url.DebugString().c_str());
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
567d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (url.is_valid())
568d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    local_file_service_->ClearSyncFlagForURL(url);
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
570d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  callback.Run(status);
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::DidGetLocalChangeStatus(
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SyncFileStatusCallback& callback,
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncStatusCode status,
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool has_pending_local_changes) {
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      status,
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      has_pending_local_changes ?
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED);
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::OnSyncEnabledForRemoteSync() {
584d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  remote_sync_->Schedule();
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::OnLocalChangeAvailable(int64 pending_changes) {
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
590d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_sync_->OnChangesUpdated(pending_changes);
591d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  remote_sync_->ScheduleIfNotRunning();
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::OnRemoteChangeQueueUpdated(int64 pending_changes) {
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
597d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  remote_sync_->OnChangesUpdated(pending_changes);
598d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_sync_->ScheduleIfNotRunning();
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::OnRemoteServiceStateUpdated(
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RemoteServiceState state,
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& description) {
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  util::Log(logging::LOG_INFO, FROM_HERE,
6067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "OnRemoteServiceStateChanged: %d %s", state, description.c_str());
607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
608d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  remote_sync_->Schedule();
609d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_sync_->Schedule();
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SyncEventObserver, observers_,
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      OnSyncStateUpdated(GURL(),
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         RemoteStateToSyncServiceState(state),
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         description));
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::Observe(
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int type,
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::NotificationSource& source,
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::NotificationDetails& details) {
622c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Event notification sequence.
623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // (User action)    (Notification type)
625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Install:         INSTALLED.
626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Update:          INSTALLED.
627a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Uninstall:       UNINSTALLED.
628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Launch, Close:   No notification.
629868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Enable:          ENABLED.
630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Disable:         UNLOADED(DISABLE).
631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED.
632c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (type) {
634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      HandleExtensionInstalled(details);
636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      HandleExtensionUnloaded(type, details);
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
640a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
641a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      HandleExtensionUninstalled(type, details);
642a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      break;
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_ENABLED:
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      HandleExtensionEnabled(type, details);
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED() << "Unknown notification.";
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SyncFileSystemService::HandleExtensionInstalled(
653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const content::NotificationDetails& details) {
654d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const Extension* extension =
655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::Details<const extensions::InstalledExtensionInfo>(details)->
656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          extension;
657d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin;
659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // NOTE: When an app is uninstalled and re-installed in a sequence,
660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |local_file_service_| may still keeps |app_origin| as disabled origin.
661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  local_file_service_->SetOriginEnabled(app_origin, true);
662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::HandleExtensionUnloaded(
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int type,
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::NotificationDetails& details) {
667c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::Details<const extensions::UnloadedExtensionInfo> info(details);
668a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (info->reason != extension_misc::UNLOAD_REASON_DISABLE)
669a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
670d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
671d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string extension_id = info->extension->id();
672d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  GURL app_origin = Extension::GetBaseURLFromExtensionId(extension_id);
673d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
674d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int reasons = ExtensionPrefs::Get(profile_)->GetDisableReasons(extension_id);
675d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (reasons & Extension::DISABLE_RELOAD) {
676d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Bypass disabling the origin since the app will be re-enabled soon.
677d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // NOTE: If re-enabling the app fails, the app is disabled while it is
678d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // handled as enabled origin in the SyncFS. This should be safe and will be
679d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // recovered when the user re-enables the app manually or the sync service
680d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // restarts.
681d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
682d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)             << app_origin;
683d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
684d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
685d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
686a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
687a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)           << app_origin;
68858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  remote_file_service_->DisableOrigin(
689a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      app_origin,
690a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&DidHandleOriginForExtensionUnloadedEvent,
691a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                 type, app_origin));
692a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  local_file_service_->SetOriginEnabled(app_origin, false);
693a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
695a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void SyncFileSystemService::HandleExtensionUninstalled(
696a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    int type,
697a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const content::NotificationDetails& details) {
69868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const Extension* extension = content::Details<const Extension>(details).ptr();
69968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(extension);
70068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
70168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RemoteFileSyncService::UninstallFlag flag =
70268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE;
70368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // If it's loaded from an unpacked package and with key: field,
70468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // the uninstall will not be sync'ed and the user might be using the
70568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // same app key in other installs, so avoid purging the remote folder.
70668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (extensions::Manifest::IsUnpackedLocation(extension->location()) &&
70768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      extension->manifest()->HasKey(extensions::manifest_keys::kKey)) {
70868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    flag = RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE;
70968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
71068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
71168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
712a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DVLOG(1) << "Handle extension notification for UNINSTALLED: "
713a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)           << app_origin;
714a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  remote_file_service_->UninstallOrigin(
71568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      app_origin, flag,
716a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&DidHandleOriginForExtensionUnloadedEvent,
717a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                 type, app_origin));
718a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  local_file_service_->SetOriginEnabled(app_origin, false);
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::HandleExtensionEnabled(
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int type,
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::NotificationDetails& details) {
724d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string extension_id = content::Details<const Extension>(details)->id();
725d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  GURL app_origin = Extension::GetBaseURLFromExtensionId(extension_id);
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin;
72758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  remote_file_service_->EnableOrigin(
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      app_origin,
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DidHandleOriginForExtensionEnabledEvent, type, app_origin));
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  local_file_service_->SetOriginEnabled(app_origin, true);
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::OnStateChanged() {
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ProfileSyncServiceBase* profile_sync_service =
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ProfileSyncServiceFactory::GetForProfile(profile_);
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (profile_sync_service)
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UpdateSyncEnabledStatus(profile_sync_service);
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::OnFileStatusChanged(
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FileSystemURL& url,
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncFileStatus sync_status,
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncAction action_taken,
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncDirection direction) {
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SyncEventObserver, observers_,
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      OnFileSynced(url, sync_status, action_taken, direction));
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncFileSystemService::UpdateSyncEnabledStatus(
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ProfileSyncServiceBase* profile_sync_service) {
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!profile_sync_service->HasSyncSetupCompleted())
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
754d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bool old_sync_enabled = sync_enabled_;
755868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::APPS);
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remote_file_service_->SetSyncEnabled(sync_enabled_);
758d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!old_sync_enabled && sync_enabled_) {
759d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    local_sync_->Schedule();
760d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    remote_sync_->Schedule();
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace sync_file_system
765