Home | History | Annotate | Download | only in drive_backend_v1
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <utility>
     10 
     11 #include "base/bind.h"
     12 #include "base/file_util.h"
     13 #include "base/location.h"
     14 #include "base/memory/weak_ptr.h"
     15 #include "base/message_loop/message_loop_proxy.h"
     16 #include "base/strings/utf_string_conversions.h"
     17 #include "base/values.h"
     18 #include "chrome/browser/drive/drive_api_util.h"
     19 #include "chrome/browser/drive/drive_notification_manager.h"
     20 #include "chrome/browser/drive/drive_notification_manager_factory.h"
     21 #include "chrome/browser/extensions/extension_service.h"
     22 #include "chrome/browser/extensions/extension_system.h"
     23 #include "chrome/browser/profiles/profile.h"
     24 #include "chrome/browser/sync_file_system/drive_backend_v1/api_util.h"
     25 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_util.h"
     26 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_metadata_store.h"
     27 #include "chrome/browser/sync_file_system/drive_backend_v1/local_sync_delegate.h"
     28 #include "chrome/browser/sync_file_system/drive_backend_v1/remote_sync_delegate.h"
     29 #include "chrome/browser/sync_file_system/file_status_observer.h"
     30 #include "chrome/browser/sync_file_system/logger.h"
     31 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
     32 #include "chrome/browser/sync_file_system/sync_file_system.pb.h"
     33 #include "chrome/browser/sync_file_system/sync_file_type.h"
     34 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     35 #include "content/public/browser/browser_thread.h"
     36 #include "extensions/common/constants.h"
     37 #include "extensions/common/extension.h"
     38 #include "webkit/browser/fileapi/file_system_url.h"
     39 #include "webkit/common/blob/scoped_file.h"
     40 #include "webkit/common/fileapi/file_system_util.h"
     41 
     42 using fileapi::FileSystemURL;
     43 
     44 namespace sync_file_system {
     45 
     46 typedef RemoteFileSyncService::OriginStatusMap OriginStatusMap;
     47 
     48 namespace {
     49 
     50 const base::FilePath::CharType kTempDirName[] = FILE_PATH_LITERAL("tmp");
     51 
     52 void EmptyStatusCallback(SyncStatusCode status) {}
     53 
     54 void RemoteVersionsCallbackAdapter(
     55     const DriveFileSyncService::RemoteVersionsCallback& versions_callback,
     56     const SyncStatusCallback& completion_callback,
     57     SyncStatusCode status,
     58     const std::vector<DriveFileSyncService::Version>& versions) {
     59   completion_callback.Run(status);
     60   versions_callback.Run(status, versions);
     61 }
     62 
     63 void DownloadVersionCallbackAdapter(
     64     const DriveFileSyncService::DownloadVersionCallback& download_callback,
     65     const SyncStatusCallback& completion_callback,
     66     SyncStatusCode status,
     67     webkit_blob::ScopedFile downloaded) {
     68   completion_callback.Run(status);
     69   download_callback.Run(status, downloaded.Pass());
     70 }
     71 
     72 }  // namespace
     73 
     74 ConflictResolutionPolicy DriveFileSyncService::kDefaultPolicy =
     75     CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN;
     76 
     77 // DriveFileSyncService ------------------------------------------------------
     78 
     79 DriveFileSyncService::~DriveFileSyncService() {
     80   if (api_util_)
     81     api_util_->RemoveObserver(this);
     82 
     83   drive::DriveNotificationManager* drive_notification_manager =
     84       drive::DriveNotificationManagerFactory::GetForBrowserContext(profile_);
     85   if (drive_notification_manager)
     86     drive_notification_manager->RemoveObserver(this);
     87 }
     88 
     89 scoped_ptr<DriveFileSyncService> DriveFileSyncService::Create(
     90     Profile* profile) {
     91   scoped_ptr<DriveFileSyncService> service(new DriveFileSyncService(profile));
     92   scoped_ptr<SyncTaskManager> task_manager(
     93       new SyncTaskManager(service->AsWeakPtr()));
     94   SyncStatusCallback callback = base::Bind(
     95       &SyncTaskManager::Initialize, task_manager->AsWeakPtr());
     96   service->Initialize(task_manager.Pass(), callback);
     97   return service.Pass();
     98 }
     99 
    100 void DriveFileSyncService::AppendDependsOnFactories(
    101     std::set<BrowserContextKeyedServiceFactory*>* factories) {
    102   DCHECK(factories);
    103   factories->insert(drive::DriveNotificationManagerFactory::GetInstance());
    104   factories->insert(ProfileOAuth2TokenServiceFactory::GetInstance());
    105   factories->insert(extensions::ExtensionSystemFactory::GetInstance());
    106 }
    107 
    108 scoped_ptr<DriveFileSyncService> DriveFileSyncService::CreateForTesting(
    109     Profile* profile,
    110     const base::FilePath& base_dir,
    111     scoped_ptr<drive_backend::APIUtilInterface> api_util,
    112     scoped_ptr<DriveMetadataStore> metadata_store) {
    113   scoped_ptr<DriveFileSyncService> service(new DriveFileSyncService(profile));
    114   scoped_ptr<SyncTaskManager> task_manager(
    115       new SyncTaskManager(service->AsWeakPtr()));
    116   SyncStatusCallback callback = base::Bind(
    117       &SyncTaskManager::Initialize, task_manager->AsWeakPtr());
    118   service->InitializeForTesting(task_manager.Pass(),
    119                                 base_dir,
    120                                 api_util.Pass(),
    121                                 metadata_store.Pass(),
    122                                 callback);
    123   return service.Pass();
    124 }
    125 
    126 void DriveFileSyncService::AddServiceObserver(Observer* observer) {
    127   service_observers_.AddObserver(observer);
    128 }
    129 
    130 void DriveFileSyncService::AddFileStatusObserver(
    131     FileStatusObserver* observer) {
    132   file_status_observers_.AddObserver(observer);
    133 }
    134 
    135 void DriveFileSyncService::RegisterOrigin(
    136     const GURL& origin,
    137     const SyncStatusCallback& callback) {
    138   if (!pending_origin_operations_.HasPendingOperation(origin) &&
    139       metadata_store_->IsIncrementalSyncOrigin(origin) &&
    140       !metadata_store_->GetResourceIdForOrigin(origin).empty()) {
    141     DCHECK(!metadata_store_->IsOriginDisabled(origin));
    142     callback.Run(SYNC_STATUS_OK);
    143     MaybeStartFetchChanges();
    144     return;
    145   }
    146 
    147   pending_origin_operations_.Push(origin, OriginOperation::REGISTERING);
    148 
    149   task_manager_->ScheduleTaskAtPriority(
    150       base::Bind(&DriveFileSyncService::DoRegisterOrigin, AsWeakPtr(), origin),
    151       SyncTaskManager::PRIORITY_HIGH,
    152       callback);
    153 }
    154 
    155 void DriveFileSyncService::EnableOrigin(
    156     const GURL& origin,
    157     const SyncStatusCallback& callback) {
    158   pending_origin_operations_.Push(origin, OriginOperation::ENABLING);
    159   task_manager_->ScheduleTaskAtPriority(
    160       base::Bind(&DriveFileSyncService::DoEnableOrigin, AsWeakPtr(), origin),
    161       SyncTaskManager::PRIORITY_HIGH,
    162       callback);
    163 }
    164 
    165 void DriveFileSyncService::DisableOrigin(
    166     const GURL& origin,
    167     const SyncStatusCallback& callback) {
    168   pending_origin_operations_.Push(origin, OriginOperation::DISABLING);
    169   task_manager_->ScheduleTaskAtPriority(
    170       base::Bind(&DriveFileSyncService::DoDisableOrigin, AsWeakPtr(), origin),
    171       SyncTaskManager::PRIORITY_HIGH,
    172       callback);
    173 }
    174 
    175 void DriveFileSyncService::UninstallOrigin(
    176     const GURL& origin,
    177     UninstallFlag flag,
    178     const SyncStatusCallback& callback) {
    179   pending_origin_operations_.Push(origin, OriginOperation::UNINSTALLING);
    180   task_manager_->ScheduleTaskAtPriority(
    181       base::Bind(&DriveFileSyncService::DoUninstallOrigin, AsWeakPtr(),
    182                  origin, flag),
    183       SyncTaskManager::PRIORITY_HIGH,
    184       callback);
    185 }
    186 
    187 void DriveFileSyncService::ProcessRemoteChange(
    188     const SyncFileCallback& callback) {
    189   task_manager_->ScheduleTask(
    190       base::Bind(&DriveFileSyncService::DoProcessRemoteChange, AsWeakPtr(),
    191                  callback),
    192       base::Bind(&EmptyStatusCallback));
    193 }
    194 
    195 void DriveFileSyncService::SetRemoteChangeProcessor(
    196     RemoteChangeProcessor* processor) {
    197   remote_change_processor_ = processor;
    198 }
    199 
    200 LocalChangeProcessor* DriveFileSyncService::GetLocalChangeProcessor() {
    201   return this;
    202 }
    203 
    204 bool DriveFileSyncService::IsConflicting(const FileSystemURL& url) {
    205   DriveMetadata metadata;
    206   const SyncStatusCode status = metadata_store_->ReadEntry(url, &metadata);
    207   if (status != SYNC_STATUS_OK) {
    208     DCHECK_EQ(SYNC_DATABASE_ERROR_NOT_FOUND, status);
    209     return false;
    210   }
    211   return metadata.conflicted();
    212 }
    213 
    214 RemoteServiceState DriveFileSyncService::GetCurrentState() const {
    215   if (!sync_enabled_)
    216     return REMOTE_SERVICE_DISABLED;
    217   return state_;
    218 }
    219 
    220 void DriveFileSyncService::GetOriginStatusMap(OriginStatusMap* status_map) {
    221   DCHECK(status_map);
    222 
    223   // Add batch sync origins held by DriveFileSyncService.
    224   typedef std::map<GURL, std::string>::const_iterator iterator;
    225   for (iterator itr = pending_batch_sync_origins_.begin();
    226        itr != pending_batch_sync_origins_.end();
    227        ++itr)
    228     (*status_map)[itr->first] = "Pending";
    229 
    230   // Add incremental and disabled origins held by DriveMetadataStore.
    231   for (iterator itr = metadata_store_->incremental_sync_origins().begin();
    232        itr != metadata_store_->incremental_sync_origins().end();
    233        ++itr)
    234     (*status_map)[itr->first] = "Enabled";
    235 
    236   for (iterator itr = metadata_store_->disabled_origins().begin();
    237        itr != metadata_store_->disabled_origins().end();
    238        ++itr)
    239     (*status_map)[itr->first] = "Disabled";
    240 }
    241 
    242 scoped_ptr<base::ListValue> DriveFileSyncService::DumpFiles(
    243     const GURL& origin) {
    244   return metadata_store_->DumpFiles(origin);
    245 }
    246 
    247 scoped_ptr<base::ListValue> DriveFileSyncService::DumpDatabase() {
    248   // Not implemented (yet).
    249   return scoped_ptr<base::ListValue>();
    250 }
    251 
    252 void DriveFileSyncService::SetSyncEnabled(bool enabled) {
    253   if (sync_enabled_ == enabled)
    254     return;
    255 
    256   RemoteServiceState old_state = GetCurrentState();
    257   sync_enabled_ = enabled;
    258   if (old_state == GetCurrentState())
    259     return;
    260 
    261   const char* status_message = enabled ? "Sync is enabled" : "Sync is disabled";
    262   FOR_EACH_OBSERVER(
    263       Observer, service_observers_,
    264       OnRemoteServiceStateUpdated(GetCurrentState(), status_message));
    265 }
    266 
    267 SyncStatusCode DriveFileSyncService::SetConflictResolutionPolicy(
    268     ConflictResolutionPolicy policy) {
    269   conflict_resolution_resolver_.set_policy(policy);
    270   return SYNC_STATUS_OK;
    271 }
    272 
    273 ConflictResolutionPolicy
    274 DriveFileSyncService::GetConflictResolutionPolicy() const {
    275   return conflict_resolution_resolver_.policy();
    276 }
    277 
    278 void DriveFileSyncService::GetRemoteVersions(
    279     const fileapi::FileSystemURL& url,
    280     const RemoteVersionsCallback& callback) {
    281   task_manager_->ScheduleTask(
    282       base::Bind(&DriveFileSyncService::DoGetRemoteVersions, AsWeakPtr(),
    283                  url, callback),
    284       base::Bind(&EmptyStatusCallback));
    285 }
    286 
    287 void DriveFileSyncService::DownloadRemoteVersion(
    288     const fileapi::FileSystemURL& url,
    289     const std::string& version_id,
    290     const DownloadVersionCallback& callback) {
    291   task_manager_->ScheduleTask(
    292       base::Bind(&DriveFileSyncService::DoDownloadRemoteVersion, AsWeakPtr(),
    293                  url, version_id, callback),
    294       base::Bind(&EmptyStatusCallback));
    295 }
    296 
    297 void DriveFileSyncService::ApplyLocalChange(
    298     const FileChange& local_file_change,
    299     const base::FilePath& local_file_path,
    300     const SyncFileMetadata& local_file_metadata,
    301     const FileSystemURL& url,
    302     const SyncStatusCallback& callback) {
    303   task_manager_->ScheduleTask(
    304       base::Bind(&DriveFileSyncService::DoApplyLocalChange, AsWeakPtr(),
    305                  local_file_change,
    306                  local_file_path,
    307                  local_file_metadata,
    308                  url),
    309       callback);
    310 }
    311 
    312 void DriveFileSyncService::OnAuthenticated() {
    313   if (state_ == REMOTE_SERVICE_OK)
    314     return;
    315   util::Log(logging::LOG_INFO, FROM_HERE, "OnAuthenticated");
    316 
    317   UpdateServiceState(REMOTE_SERVICE_OK, "Authenticated");
    318 
    319   may_have_unfetched_changes_ = true;
    320   MaybeStartFetchChanges();
    321 }
    322 
    323 void DriveFileSyncService::OnNetworkConnected() {
    324   if (state_ == REMOTE_SERVICE_OK)
    325     return;
    326   util::Log(logging::LOG_INFO, FROM_HERE, "OnNetworkConnected");
    327 
    328   UpdateServiceState(REMOTE_SERVICE_OK, "Network connected");
    329 
    330   may_have_unfetched_changes_ = true;
    331   MaybeStartFetchChanges();
    332 }
    333 
    334 DriveFileSyncService::DriveFileSyncService(Profile* profile)
    335     : profile_(profile),
    336       state_(REMOTE_SERVICE_OK),
    337       sync_enabled_(true),
    338       largest_fetched_changestamp_(0),
    339       may_have_unfetched_changes_(false),
    340       remote_change_processor_(NULL),
    341       last_gdata_error_(google_apis::HTTP_SUCCESS),
    342       conflict_resolution_resolver_(kDefaultPolicy) {
    343 }
    344 
    345 void DriveFileSyncService::Initialize(
    346     scoped_ptr<SyncTaskManager> task_manager,
    347     const SyncStatusCallback& callback) {
    348   DCHECK(profile_);
    349   DCHECK(!metadata_store_);
    350   DCHECK(!task_manager_);
    351 
    352   task_manager_ = task_manager.Pass();
    353 
    354   temporary_file_dir_ = sync_file_system::GetSyncFileSystemDir(
    355       profile_->GetPath()).Append(kTempDirName);
    356 
    357   api_util_.reset(new drive_backend::APIUtil(profile_, temporary_file_dir_));
    358   api_util_->AddObserver(this);
    359 
    360   metadata_store_.reset(new DriveMetadataStore(
    361       GetSyncFileSystemDir(profile_->GetPath()),
    362       content::BrowserThread::GetMessageLoopProxyForThread(
    363           content::BrowserThread::FILE).get()));
    364 
    365   metadata_store_->Initialize(
    366       base::Bind(&DriveFileSyncService::DidInitializeMetadataStore,
    367                  AsWeakPtr(), callback));
    368 }
    369 
    370 void DriveFileSyncService::InitializeForTesting(
    371     scoped_ptr<SyncTaskManager> task_manager,
    372     const base::FilePath& base_dir,
    373     scoped_ptr<drive_backend::APIUtilInterface> api_util,
    374     scoped_ptr<DriveMetadataStore> metadata_store,
    375     const SyncStatusCallback& callback) {
    376   DCHECK(!metadata_store_);
    377   DCHECK(!task_manager_);
    378 
    379   task_manager_ = task_manager.Pass();
    380   temporary_file_dir_ = base_dir.Append(kTempDirName);
    381 
    382   api_util_ = api_util.Pass();
    383   metadata_store_ = metadata_store.Pass();
    384 
    385   base::MessageLoopProxy::current()->PostTask(
    386       FROM_HERE,
    387       base::Bind(&DriveFileSyncService::DidInitializeMetadataStore,
    388                  AsWeakPtr(), callback, SYNC_STATUS_OK, false));
    389 }
    390 
    391 void DriveFileSyncService::DidInitializeMetadataStore(
    392     const SyncStatusCallback& callback,
    393     SyncStatusCode status,
    394     bool created) {
    395   if (status != SYNC_STATUS_OK) {
    396     callback.Run(status);
    397     return;
    398   }
    399 
    400   DCHECK(pending_batch_sync_origins_.empty());
    401 
    402   UpdateRegisteredOrigins();
    403 
    404   largest_fetched_changestamp_ = metadata_store_->GetLargestChangeStamp();
    405 
    406   DriveMetadataStore::URLAndDriveMetadataList to_be_fetched_files;
    407   status = metadata_store_->GetToBeFetchedFiles(&to_be_fetched_files);
    408   DCHECK_EQ(SYNC_STATUS_OK, status);
    409   typedef DriveMetadataStore::URLAndDriveMetadataList::const_iterator iterator;
    410   for (iterator itr = to_be_fetched_files.begin();
    411        itr != to_be_fetched_files.end(); ++itr) {
    412     const FileSystemURL& url = itr->first;
    413     const DriveMetadata& metadata = itr->second;
    414     const std::string& resource_id = metadata.resource_id();
    415 
    416     SyncFileType file_type = SYNC_FILE_TYPE_FILE;
    417     if (metadata.type() == DriveMetadata::RESOURCE_TYPE_FOLDER)
    418       file_type = SYNC_FILE_TYPE_DIRECTORY;
    419     if (!metadata_store_->IsIncrementalSyncOrigin(url.origin())) {
    420       metadata_store_->DeleteEntry(url, base::Bind(&EmptyStatusCallback));
    421       continue;
    422     }
    423     AppendFetchChange(url.origin(), url.path(), resource_id, file_type);
    424   }
    425 
    426   if (!sync_root_resource_id().empty())
    427     api_util_->EnsureSyncRootIsNotInMyDrive(sync_root_resource_id());
    428 
    429   callback.Run(status);
    430   may_have_unfetched_changes_ = true;
    431 
    432   drive::DriveNotificationManager* drive_notification_manager =
    433       drive::DriveNotificationManagerFactory::GetForBrowserContext(profile_);
    434   if (drive_notification_manager)
    435     drive_notification_manager->AddObserver(this);
    436 }
    437 
    438 void DriveFileSyncService::UpdateServiceStateFromLastOperationStatus(
    439     SyncStatusCode sync_status,
    440     google_apis::GDataErrorCode gdata_error) {
    441   switch (sync_status) {
    442     case SYNC_STATUS_OK:
    443       // If the last Drive-related operation was successful we can
    444       // change the service state to OK.
    445       if (GDataErrorCodeToSyncStatusCode(gdata_error) == SYNC_STATUS_OK)
    446         UpdateServiceState(REMOTE_SERVICE_OK, std::string());
    447       break;
    448 
    449     // Authentication error.
    450     case SYNC_STATUS_AUTHENTICATION_FAILED:
    451       UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
    452                          "Authentication required");
    453       break;
    454 
    455     // OAuth token error.
    456     case SYNC_STATUS_ACCESS_FORBIDDEN:
    457       UpdateServiceState(REMOTE_SERVICE_AUTHENTICATION_REQUIRED,
    458                          "Access forbidden");
    459       break;
    460 
    461     // Errors which could make the service temporarily unavailable.
    462     case SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE:
    463     case SYNC_STATUS_NETWORK_ERROR:
    464     case SYNC_STATUS_ABORT:
    465     case SYNC_STATUS_FAILED:
    466       UpdateServiceState(REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
    467                          "Network or temporary service error.");
    468       break;
    469 
    470     // Errors which would require manual user intervention to resolve.
    471     case SYNC_DATABASE_ERROR_CORRUPTION:
    472     case SYNC_DATABASE_ERROR_IO_ERROR:
    473     case SYNC_DATABASE_ERROR_FAILED:
    474       UpdateServiceState(REMOTE_SERVICE_DISABLED,
    475                          "Unrecoverable database error");
    476       break;
    477 
    478     default:
    479       // Other errors don't affect service state
    480       break;
    481   }
    482 }
    483 
    484 void DriveFileSyncService::UpdateServiceState(RemoteServiceState state,
    485                                               const std::string& description) {
    486   RemoteServiceState old_state = GetCurrentState();
    487   state_ = state;
    488 
    489   // Notify remote sync service state if the state has been changed.
    490   if (old_state != GetCurrentState()) {
    491     util::Log(logging::LOG_INFO, FROM_HERE,
    492               "Service state changed: %d->%d: %s",
    493               old_state, GetCurrentState(), description.c_str());
    494     FOR_EACH_OBSERVER(
    495         Observer, service_observers_,
    496         OnRemoteServiceStateUpdated(GetCurrentState(), description));
    497   }
    498 }
    499 
    500 void DriveFileSyncService::DoRegisterOrigin(
    501     const GURL& origin,
    502     const SyncStatusCallback& callback) {
    503   DCHECK(origin.SchemeIs(extensions::kExtensionScheme));
    504 
    505   OriginOperation op = pending_origin_operations_.Pop();
    506   DCHECK_EQ(origin, op.origin);
    507   DCHECK_EQ(OriginOperation::REGISTERING, op.type);
    508 
    509   DCHECK(!metadata_store_->IsOriginDisabled(origin));
    510   if (!metadata_store_->GetResourceIdForOrigin(origin).empty()) {
    511     callback.Run(SYNC_STATUS_OK);
    512     return;
    513   }
    514 
    515   EnsureOriginRootDirectory(
    516       origin, base::Bind(&DriveFileSyncService::DidGetDriveDirectoryForOrigin,
    517                          AsWeakPtr(), origin, callback));
    518 }
    519 
    520 void DriveFileSyncService::DoEnableOrigin(
    521     const GURL& origin,
    522     const SyncStatusCallback& callback) {
    523   OriginOperation op = pending_origin_operations_.Pop();
    524   DCHECK_EQ(origin, op.origin);
    525   DCHECK_EQ(OriginOperation::ENABLING, op.type);
    526 
    527   // If origin cannot be found in disabled list, then it's not a SyncFS app
    528   // and should be ignored.
    529   if (!metadata_store_->IsOriginDisabled(origin)) {
    530     callback.Run(SYNC_STATUS_OK);
    531     return;
    532   }
    533 
    534   pending_batch_sync_origins_.insert(
    535       *metadata_store_->disabled_origins().find(origin));
    536   metadata_store_->EnableOrigin(origin, callback);
    537 }
    538 
    539 void DriveFileSyncService::DoDisableOrigin(
    540     const GURL& origin,
    541     const SyncStatusCallback& callback) {
    542   OriginOperation op = pending_origin_operations_.Pop();
    543   DCHECK_EQ(origin, op.origin);
    544   DCHECK_EQ(OriginOperation::DISABLING, op.type);
    545 
    546   pending_batch_sync_origins_.erase(origin);
    547   if (!metadata_store_->IsIncrementalSyncOrigin(origin)) {
    548     callback.Run(SYNC_STATUS_OK);
    549     return;
    550   }
    551 
    552   remote_change_handler_.RemoveChangesForOrigin(origin);
    553   metadata_store_->DisableOrigin(origin, callback);
    554 }
    555 
    556 void DriveFileSyncService::DoUninstallOrigin(
    557     const GURL& origin,
    558     UninstallFlag flag,
    559     const SyncStatusCallback& callback) {
    560   OriginOperation op = pending_origin_operations_.Pop();
    561   DCHECK_EQ(origin, op.origin);
    562   DCHECK_EQ(OriginOperation::UNINSTALLING, op.type);
    563 
    564   // Because origin management is now split between DriveFileSyncService and
    565   // DriveMetadataStore, resource_id must be checked for in two places.
    566   std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin);
    567   if (resource_id.empty()) {
    568     std::map<GURL, std::string>::const_iterator iterator =
    569         pending_batch_sync_origins_.find(origin);
    570     if (iterator != pending_batch_sync_origins_.end())
    571       resource_id = iterator->second;
    572   }
    573 
    574   // An empty resource_id indicates either one of following two cases:
    575   // 1) origin is not in metadata_store_ because the extension was never
    576   //    run or it's not managed by this service, and thus no
    577   //    origin directory on the remote drive was created.
    578   // 2) origin or sync root folder is deleted on Drive.
    579   if (resource_id.empty()) {
    580     if (metadata_store_->IsKnownOrigin(origin))
    581       DidUninstallOrigin(origin, callback, google_apis::HTTP_SUCCESS);
    582     else
    583       callback.Run(SYNC_STATUS_UNKNOWN_ORIGIN);
    584     return;
    585   }
    586 
    587   if (flag == UNINSTALL_AND_KEEP_REMOTE) {
    588     DidUninstallOrigin(origin, callback, google_apis::HTTP_SUCCESS);
    589     return;
    590   }
    591 
    592   // Convert origin's directory GURL to ResourceID and delete it. Expected MD5
    593   // is empty to force delete (i.e. skip conflict resolution).
    594   api_util_->DeleteFile(resource_id,
    595                         std::string(),
    596                         base::Bind(&DriveFileSyncService::DidUninstallOrigin,
    597                                    AsWeakPtr(),
    598                                    origin,
    599                                    callback));
    600 }
    601 
    602 void DriveFileSyncService::DoProcessRemoteChange(
    603     const SyncFileCallback& sync_callback,
    604     const SyncStatusCallback& completion_callback) {
    605   DCHECK(remote_change_processor_);
    606 
    607   SyncStatusCallback callback = base::Bind(
    608       &DriveFileSyncService::DidProcessRemoteChange, AsWeakPtr(),
    609       sync_callback, completion_callback);
    610 
    611   if (GetCurrentState() == REMOTE_SERVICE_DISABLED) {
    612     callback.Run(SYNC_STATUS_SYNC_DISABLED);
    613     return;
    614   }
    615 
    616   if (!remote_change_handler_.HasChanges()) {
    617     callback.Run(SYNC_STATUS_NO_CHANGE_TO_SYNC);
    618     return;
    619   }
    620 
    621   RemoteChangeHandler::RemoteChange remote_change;
    622   bool has_remote_change =
    623       remote_change_handler_.GetChange(&remote_change);
    624   DCHECK(has_remote_change);
    625 
    626   DCHECK(!running_remote_sync_task_);
    627   running_remote_sync_task_.reset(new drive_backend::RemoteSyncDelegate(
    628       this, remote_change));
    629   running_remote_sync_task_->Run(callback);
    630 }
    631 
    632 void DriveFileSyncService::DoApplyLocalChange(
    633     const FileChange& local_file_change,
    634     const base::FilePath& local_file_path,
    635     const SyncFileMetadata& local_file_metadata,
    636     const FileSystemURL& url,
    637     const SyncStatusCallback& callback) {
    638   if (GetCurrentState() == REMOTE_SERVICE_DISABLED) {
    639     callback.Run(SYNC_STATUS_SYNC_DISABLED);
    640     return;
    641   }
    642 
    643   if (!metadata_store_->IsIncrementalSyncOrigin(url.origin())) {
    644     // We may get called by LocalFileSyncService to sync local changes
    645     // for the origins that are disabled.
    646     DVLOG(1) << "Got request for stray origin: " << url.origin().spec();
    647     callback.Run(SYNC_STATUS_UNKNOWN_ORIGIN);
    648     return;
    649   }
    650 
    651   DCHECK(!running_local_sync_task_);
    652   running_local_sync_task_.reset(new drive_backend::LocalSyncDelegate(
    653       this, local_file_change, local_file_path, local_file_metadata, url));
    654   running_local_sync_task_->Run(base::Bind(
    655       &DriveFileSyncService::DidApplyLocalChange, AsWeakPtr(), callback));
    656 }
    657 
    658 void DriveFileSyncService::DoGetRemoteVersions(
    659     const fileapi::FileSystemURL& url,
    660     const RemoteVersionsCallback& versions_callback,
    661     const SyncStatusCallback& completion_callback) {
    662   RemoteVersionsCallback callback =
    663       base::Bind(&RemoteVersionsCallbackAdapter,
    664                  versions_callback, completion_callback);
    665 
    666   DriveMetadata drive_metadata;
    667   SyncStatusCode status = metadata_store_->ReadEntry(url, &drive_metadata);
    668   if (drive_metadata.resource_id().empty())
    669     status = SYNC_DATABASE_ERROR_NOT_FOUND;
    670   if (status != SYNC_STATUS_OK) {
    671     callback.Run(status, std::vector<Version>());
    672     return;
    673   }
    674 
    675   api_util_->GetResourceEntry(
    676       drive_metadata.resource_id(),
    677       base::Bind(
    678           &DriveFileSyncService::DidGetEntryForRemoteVersions,
    679           AsWeakPtr(), callback));
    680 }
    681 
    682 void DriveFileSyncService::DidGetEntryForRemoteVersions(
    683     const RemoteVersionsCallback& callback,
    684     google_apis::GDataErrorCode error,
    685     scoped_ptr<google_apis::ResourceEntry> entry) {
    686   if (error != google_apis::HTTP_SUCCESS) {
    687     callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error),
    688                  std::vector<Version>());
    689     return;
    690   }
    691   DCHECK(entry);
    692 
    693   SyncFileType file_type =
    694       entry->is_file() ? SYNC_FILE_TYPE_FILE :
    695       entry->is_folder() ? SYNC_FILE_TYPE_DIRECTORY :
    696       SYNC_FILE_TYPE_UNKNOWN;
    697 
    698   Version version;
    699   version.id = "dummy";  // Not used in the current version.
    700   version.metadata = SyncFileMetadata(file_type,
    701                                       entry->file_size(),
    702                                       entry->updated_time());
    703   std::vector<Version> versions;
    704   versions.push_back(version);
    705   callback.Run(SYNC_STATUS_OK, versions);
    706 }
    707 
    708 void DriveFileSyncService::DoDownloadRemoteVersion(
    709     const fileapi::FileSystemURL& url,
    710     const std::string& /* version_id */,
    711     const DownloadVersionCallback& download_callback,
    712     const SyncStatusCallback& completion_callback) {
    713   DownloadVersionCallback callback =
    714       base::Bind(&DownloadVersionCallbackAdapter,
    715                  download_callback, completion_callback);
    716 
    717   DriveMetadata metadata;
    718   if (metadata_store_->ReadEntry(url, &metadata) != SYNC_STATUS_OK) {
    719     // The conflict may have been already resolved.
    720     callback.Run(SYNC_FILE_ERROR_NOT_FOUND, webkit_blob::ScopedFile());
    721     return;
    722   }
    723 
    724   api_util_->DownloadFile(
    725       metadata.resource_id(), std::string(),
    726       base::Bind(&DriveFileSyncService::DidDownloadVersion, AsWeakPtr(),
    727                  callback));
    728 }
    729 
    730 void DriveFileSyncService::DidDownloadVersion(
    731     const DownloadVersionCallback& download_callback,
    732     google_apis::GDataErrorCode error,
    733     const std::string& file_md5,
    734     int64 file_size,
    735     const base::Time& last_updated,
    736     webkit_blob::ScopedFile downloaded) {
    737   SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
    738   download_callback.Run(status, downloaded.Pass());
    739 }
    740 
    741 void DriveFileSyncService::UpdateRegisteredOrigins() {
    742   ExtensionService* extension_service =
    743       extensions::ExtensionSystem::Get(profile_)->extension_service();
    744   DCHECK(pending_batch_sync_origins_.empty());
    745   if (!extension_service)
    746     return;
    747 
    748   std::vector<GURL> origins;
    749   metadata_store_->GetAllOrigins(&origins);
    750 
    751   // Update the status of every origin using status from ExtensionService.
    752   for (std::vector<GURL>::const_iterator itr = origins.begin();
    753        itr != origins.end(); ++itr) {
    754     std::string extension_id = itr->host();
    755     GURL origin =
    756         extensions::Extension::GetBaseURLFromExtensionId(extension_id);
    757 
    758     if (!extension_service->GetInstalledExtension(extension_id)) {
    759       // Extension has been uninstalled.
    760       // (At this stage we can't know if it was unpacked extension or not,
    761       // so just purge the remote folder.)
    762       UninstallOrigin(origin,
    763                       RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE,
    764                       base::Bind(&EmptyStatusCallback));
    765     } else if (metadata_store_->IsIncrementalSyncOrigin(origin) &&
    766                !extension_service->IsExtensionEnabled(extension_id)) {
    767       // Incremental Extension has been disabled.
    768       metadata_store_->DisableOrigin(origin, base::Bind(&EmptyStatusCallback));
    769     } else if (metadata_store_->IsOriginDisabled(origin) &&
    770                extension_service->IsExtensionEnabled(extension_id)) {
    771       // Extension has been re-enabled.
    772       pending_batch_sync_origins_.insert(
    773           *metadata_store_->disabled_origins().find(origin));
    774       metadata_store_->EnableOrigin(origin, base::Bind(&EmptyStatusCallback));
    775     }
    776   }
    777 }
    778 
    779 void DriveFileSyncService::StartBatchSync(
    780     const SyncStatusCallback& callback) {
    781   DCHECK(GetCurrentState() == REMOTE_SERVICE_OK || may_have_unfetched_changes_);
    782   DCHECK(!pending_batch_sync_origins_.empty());
    783 
    784   GURL origin = pending_batch_sync_origins_.begin()->first;
    785   std::string resource_id = pending_batch_sync_origins_.begin()->second;
    786   DCHECK(!resource_id.empty());
    787   pending_batch_sync_origins_.erase(pending_batch_sync_origins_.begin());
    788 
    789   DCHECK(!metadata_store_->IsOriginDisabled(origin));
    790 
    791   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    792             "Start batch sync for: %s", origin.spec().c_str());
    793 
    794   api_util_->GetLargestChangeStamp(
    795       base::Bind(&DriveFileSyncService::DidGetLargestChangeStampForBatchSync,
    796                  AsWeakPtr(),
    797                  callback,
    798                  origin,
    799                  resource_id));
    800 
    801   may_have_unfetched_changes_ = false;
    802 }
    803 
    804 void DriveFileSyncService::DidGetDriveDirectoryForOrigin(
    805     const GURL& origin,
    806     const SyncStatusCallback& callback,
    807     SyncStatusCode status,
    808     const std::string& resource_id) {
    809   if (status == SYNC_FILE_ERROR_NOT_FOUND &&
    810       !sync_root_resource_id().empty()) {
    811     // Retry after (re-)creating the sync root directory.
    812     metadata_store_->SetSyncRootDirectory(std::string());
    813     EnsureOriginRootDirectory(
    814         origin, base::Bind(
    815             &DriveFileSyncService::DidGetDriveDirectoryForOrigin,
    816             AsWeakPtr(), origin, callback));
    817     return;
    818   }
    819 
    820   if (status != SYNC_STATUS_OK) {
    821     callback.Run(status);
    822     return;
    823   }
    824 
    825   if (!metadata_store_->IsKnownOrigin(origin))
    826     pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id));
    827 
    828   callback.Run(SYNC_STATUS_OK);
    829 }
    830 
    831 void DriveFileSyncService::DidUninstallOrigin(
    832     const GURL& origin,
    833     const SyncStatusCallback& callback,
    834     google_apis::GDataErrorCode error) {
    835   SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
    836   if (status != SYNC_STATUS_OK && status != SYNC_FILE_ERROR_NOT_FOUND) {
    837     callback.Run(status);
    838     return;
    839   }
    840 
    841   // Origin directory has been removed so it's now safe to remove the origin
    842   // from the metadata store.
    843   remote_change_handler_.RemoveChangesForOrigin(origin);
    844   pending_batch_sync_origins_.erase(origin);
    845   metadata_store_->RemoveOrigin(origin, callback);
    846 }
    847 
    848 void DriveFileSyncService::DidGetLargestChangeStampForBatchSync(
    849     const SyncStatusCallback& callback,
    850     const GURL& origin,
    851     const std::string& resource_id,
    852     google_apis::GDataErrorCode error,
    853     int64 largest_changestamp) {
    854   if (error != google_apis::HTTP_SUCCESS) {
    855     pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id));
    856     callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
    857     return;
    858   }
    859 
    860   if (metadata_store_->incremental_sync_origins().empty()) {
    861     largest_fetched_changestamp_ = largest_changestamp;
    862     metadata_store_->SetLargestChangeStamp(
    863         largest_changestamp,
    864         base::Bind(&EmptyStatusCallback));
    865   }
    866 
    867   api_util_->ListFiles(
    868       resource_id,
    869       base::Bind(&DriveFileSyncService::DidGetDirectoryContentForBatchSync,
    870                  AsWeakPtr(),
    871                  callback,
    872                  origin,
    873                  resource_id,
    874                  largest_changestamp));
    875 }
    876 
    877 void DriveFileSyncService::DidGetDirectoryContentForBatchSync(
    878     const SyncStatusCallback& callback,
    879     const GURL& origin,
    880     const std::string& resource_id,
    881     int64 largest_changestamp,
    882     google_apis::GDataErrorCode error,
    883     scoped_ptr<google_apis::ResourceList> feed) {
    884   if (error != google_apis::HTTP_SUCCESS) {
    885     pending_batch_sync_origins_.insert(std::make_pair(origin, resource_id));
    886     callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
    887     return;
    888   }
    889 
    890   typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator;
    891   for (iterator itr = feed->entries().begin();
    892        itr != feed->entries().end(); ++itr) {
    893     const google_apis::ResourceEntry& entry = **itr;
    894     if (entry.deleted())
    895       continue;
    896 
    897     SyncFileType file_type = SYNC_FILE_TYPE_UNKNOWN;
    898     if (entry.is_file())
    899       file_type = SYNC_FILE_TYPE_FILE;
    900     else if (entry.is_folder() && IsSyncFSDirectoryOperationEnabled())
    901       file_type = SYNC_FILE_TYPE_DIRECTORY;
    902     else
    903       continue;
    904 
    905     DCHECK(file_type == SYNC_FILE_TYPE_FILE ||
    906            file_type == SYNC_FILE_TYPE_DIRECTORY);
    907 
    908     // Save to be fetched file to DB for restore in case of crash.
    909     DriveMetadata metadata;
    910     metadata.set_resource_id(entry.resource_id());
    911     metadata.set_md5_checksum(std::string());
    912     metadata.set_conflicted(false);
    913     metadata.set_to_be_fetched(true);
    914 
    915     if (file_type == SYNC_FILE_TYPE_FILE)
    916       metadata.set_type(DriveMetadata::RESOURCE_TYPE_FILE);
    917     else
    918       metadata.set_type(DriveMetadata::RESOURCE_TYPE_FOLDER);
    919 
    920     base::FilePath path = TitleToPath(entry.title());
    921     fileapi::FileSystemURL url(CreateSyncableFileSystemURL(
    922         origin, path));
    923     // TODO(calvinlo): Write metadata and origin data as single batch command
    924     // so it's not possible for the DB to contain a DriveMetadata with an
    925     // unknown origin.
    926     metadata_store_->UpdateEntry(url, metadata,
    927                                  base::Bind(&EmptyStatusCallback));
    928 
    929     AppendFetchChange(origin, path, entry.resource_id(), file_type);
    930   }
    931 
    932   GURL next_feed_url;
    933   if (feed->GetNextFeedURL(&next_feed_url)) {
    934     api_util_->ContinueListing(
    935         next_feed_url,
    936         base::Bind(&DriveFileSyncService::DidGetDirectoryContentForBatchSync,
    937                    AsWeakPtr(),
    938                    callback,
    939                    origin,
    940                    resource_id,
    941                    largest_changestamp));
    942     return;
    943   }
    944 
    945   metadata_store_->AddIncrementalSyncOrigin(origin, resource_id);
    946   may_have_unfetched_changes_ = true;
    947   callback.Run(SYNC_STATUS_OK);
    948 }
    949 
    950 void DriveFileSyncService::DidProcessRemoteChange(
    951     const SyncFileCallback& sync_callback,
    952     const SyncStatusCallback& completion_callback,
    953     SyncStatusCode status) {
    954   fileapi::FileSystemURL url;
    955   if (running_remote_sync_task_)
    956     url = running_remote_sync_task_->url();
    957   running_remote_sync_task_.reset();
    958 
    959   completion_callback.Run(status);
    960   sync_callback.Run(status, url);
    961 }
    962 
    963 void DriveFileSyncService::DidApplyLocalChange(
    964     const SyncStatusCallback& callback,
    965     SyncStatusCode status) {
    966   running_local_sync_task_.reset();
    967   callback.Run(status);
    968 }
    969 
    970 bool DriveFileSyncService::AppendRemoteChange(
    971     const GURL& origin,
    972     const google_apis::ResourceEntry& entry,
    973     int64 changestamp) {
    974   base::FilePath path = TitleToPath(entry.title());
    975 
    976   if (!entry.is_folder() && !entry.is_file() && !entry.deleted())
    977     return false;
    978 
    979   if (entry.is_folder() && !IsSyncFSDirectoryOperationEnabled())
    980     return false;
    981 
    982   SyncFileType file_type = entry.is_file() ?
    983       SYNC_FILE_TYPE_FILE : SYNC_FILE_TYPE_DIRECTORY;
    984 
    985   return AppendRemoteChangeInternal(
    986       origin, path, entry.deleted(),
    987       entry.resource_id(), changestamp,
    988       entry.deleted() ? std::string() : entry.file_md5(),
    989       entry.updated_time(), file_type);
    990 }
    991 
    992 bool DriveFileSyncService::AppendFetchChange(
    993     const GURL& origin,
    994     const base::FilePath& path,
    995     const std::string& resource_id,
    996     SyncFileType type) {
    997   return AppendRemoteChangeInternal(
    998       origin, path,
    999       false,  // is_deleted
   1000       resource_id,
   1001       0,  // changestamp
   1002       std::string(),  // remote_file_md5
   1003       base::Time(),  // updated_time
   1004       type);
   1005 }
   1006 
   1007 bool DriveFileSyncService::AppendRemoteChangeInternal(
   1008     const GURL& origin,
   1009     const base::FilePath& path,
   1010     bool is_deleted,
   1011     const std::string& remote_resource_id,
   1012     int64 changestamp,
   1013     const std::string& remote_file_md5,
   1014     const base::Time& updated_time,
   1015     SyncFileType file_type) {
   1016   fileapi::FileSystemURL url(CreateSyncableFileSystemURL(origin, path));
   1017   DCHECK(url.is_valid());
   1018 
   1019   // Note that we create a normalized path from url.path() rather than
   1020   // path here (as FileSystemURL does extra normalization).
   1021   base::FilePath::StringType normalized_path =
   1022     fileapi::VirtualPath::GetNormalizedFilePath(url.path());
   1023 
   1024   std::string local_resource_id;
   1025   std::string local_file_md5;
   1026 
   1027   DriveMetadata metadata;
   1028   bool has_db_entry =
   1029       (metadata_store_->ReadEntry(url, &metadata) == SYNC_STATUS_OK);
   1030   if (has_db_entry) {
   1031     local_resource_id = metadata.resource_id();
   1032     if (!metadata.to_be_fetched())
   1033       local_file_md5 = metadata.md5_checksum();
   1034   }
   1035 
   1036   RemoteChangeHandler::RemoteChange pending_change;
   1037   if (remote_change_handler_.GetChangeForURL(url, &pending_change)) {
   1038     if (pending_change.changestamp >= changestamp)
   1039       return false;
   1040 
   1041     if (pending_change.change.IsDelete()) {
   1042       local_resource_id.clear();
   1043       local_file_md5.clear();
   1044     } else {
   1045       local_resource_id = pending_change.resource_id;
   1046       local_file_md5 = pending_change.md5_checksum;
   1047     }
   1048   }
   1049 
   1050   // Drop the change if remote update change does not change file content.
   1051   if (!remote_file_md5.empty() &&
   1052       !local_file_md5.empty() &&
   1053       remote_file_md5 == local_file_md5)
   1054     return false;
   1055 
   1056   // Drop the change if remote change is for directory addition that is
   1057   // already known.
   1058   if (file_type == SYNC_FILE_TYPE_DIRECTORY &&
   1059       !is_deleted &&
   1060       !local_resource_id.empty() &&
   1061       metadata.type() == DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER)
   1062     return false;
   1063 
   1064   // Drop any change if the change has unknown resource id.
   1065   if (!remote_resource_id.empty() &&
   1066       !local_resource_id.empty() &&
   1067       remote_resource_id != local_resource_id)
   1068     return false;
   1069 
   1070   if (is_deleted) {
   1071     // Drop any change if the change is for deletion and local resource id is
   1072     // empty.
   1073     if (local_resource_id.empty())
   1074       return false;
   1075 
   1076     // Determine a file type of the deleted change by local metadata.
   1077     if (!remote_resource_id.empty() &&
   1078         !local_resource_id.empty() &&
   1079         remote_resource_id == local_resource_id) {
   1080       DCHECK(IsSyncFSDirectoryOperationEnabled() ||
   1081              DriveMetadata::RESOURCE_TYPE_FILE == metadata.type());
   1082       file_type = metadata.type() == DriveMetadata::RESOURCE_TYPE_FILE ?
   1083           SYNC_FILE_TYPE_FILE : SYNC_FILE_TYPE_DIRECTORY;
   1084     }
   1085 
   1086     if (has_db_entry) {
   1087       metadata.set_resource_id(std::string());
   1088       metadata_store_->UpdateEntry(url, metadata,
   1089                                    base::Bind(&EmptyStatusCallback));
   1090     }
   1091   }
   1092 
   1093   FileChange file_change(is_deleted ? FileChange::FILE_CHANGE_DELETE
   1094                                     : FileChange::FILE_CHANGE_ADD_OR_UPDATE,
   1095                          file_type);
   1096 
   1097   RemoteChangeHandler::RemoteChange remote_change(
   1098       changestamp, remote_resource_id, remote_file_md5,
   1099       updated_time, url, file_change);
   1100   remote_change_handler_.AppendChange(remote_change);
   1101 
   1102   DVLOG(3) << "Append remote change: " << path.value()
   1103            << " (" << normalized_path << ")"
   1104            << "@" << changestamp << " "
   1105            << file_change.DebugString();
   1106 
   1107   return true;
   1108 }
   1109 
   1110 void DriveFileSyncService::RemoveRemoteChange(
   1111     const FileSystemURL& url) {
   1112   remote_change_handler_.RemoveChangeForURL(url);
   1113 }
   1114 
   1115 void DriveFileSyncService::MarkConflict(
   1116     const fileapi::FileSystemURL& url,
   1117     DriveMetadata* drive_metadata,
   1118     const SyncStatusCallback& callback) {
   1119   DCHECK(drive_metadata);
   1120   DCHECK(!drive_metadata->resource_id().empty());
   1121   drive_metadata->set_conflicted(true);
   1122   drive_metadata->set_to_be_fetched(false);
   1123   metadata_store_->UpdateEntry(
   1124       url, *drive_metadata, base::Bind(
   1125           &DriveFileSyncService::NotifyConflict,
   1126           AsWeakPtr(), url, callback));
   1127 }
   1128 
   1129 void DriveFileSyncService::NotifyConflict(
   1130     const fileapi::FileSystemURL& url,
   1131     const SyncStatusCallback& callback,
   1132     SyncStatusCode status) {
   1133   if (status != SYNC_STATUS_OK) {
   1134     callback.Run(status);
   1135     return;
   1136   }
   1137   NotifyObserversFileStatusChanged(url,
   1138                                    SYNC_FILE_STATUS_CONFLICTING,
   1139                                    SYNC_ACTION_NONE,
   1140                                    SYNC_DIRECTION_NONE);
   1141   callback.Run(status);
   1142 }
   1143 
   1144 SyncStatusCode DriveFileSyncService::GDataErrorCodeToSyncStatusCodeWrapper(
   1145     google_apis::GDataErrorCode error) {
   1146   last_gdata_error_ = error;
   1147   SyncStatusCode status = GDataErrorCodeToSyncStatusCode(error);
   1148   if (status != SYNC_STATUS_OK && !api_util_->IsAuthenticated())
   1149     return SYNC_STATUS_AUTHENTICATION_FAILED;
   1150   return status;
   1151 }
   1152 
   1153 void DriveFileSyncService::MaybeStartFetchChanges() {
   1154   if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
   1155     return;
   1156 
   1157   // If we have pending_batch_sync_origins, try starting the batch sync.
   1158   if (!pending_batch_sync_origins_.empty()) {
   1159     if (GetCurrentState() == REMOTE_SERVICE_OK || may_have_unfetched_changes_) {
   1160       task_manager_->ScheduleTaskIfIdle(
   1161           base::Bind(&DriveFileSyncService::StartBatchSync, AsWeakPtr()),
   1162           SyncStatusCallback());
   1163     }
   1164     return;
   1165   }
   1166 
   1167   if (may_have_unfetched_changes_ &&
   1168       !metadata_store_->incremental_sync_origins().empty()) {
   1169     task_manager_->ScheduleTaskIfIdle(
   1170         base::Bind(&DriveFileSyncService::FetchChangesForIncrementalSync,
   1171                    AsWeakPtr()),
   1172         SyncStatusCallback());
   1173   }
   1174 }
   1175 
   1176 void DriveFileSyncService::OnNotificationReceived() {
   1177   VLOG(2) << "Notification received to check for Google Drive updates";
   1178 
   1179   // Likely indicating the network is enabled again.
   1180   UpdateServiceState(REMOTE_SERVICE_OK, "Got push notification for Drive.");
   1181 
   1182   // TODO(calvinlo): Try to eliminate may_have_unfetched_changes_ variable.
   1183   may_have_unfetched_changes_ = true;
   1184   MaybeStartFetchChanges();
   1185 }
   1186 
   1187 void DriveFileSyncService::OnPushNotificationEnabled(bool enabled) {
   1188   VLOG(2) << "XMPP Push notification is " << (enabled ? "enabled" : "disabled");
   1189 }
   1190 
   1191 void DriveFileSyncService::MaybeScheduleNextTask() {
   1192   if (GetCurrentState() == REMOTE_SERVICE_DISABLED)
   1193     return;
   1194 
   1195   // Notify observer of the update of |pending_changes_|.
   1196   FOR_EACH_OBSERVER(Observer, service_observers_,
   1197                     OnRemoteChangeQueueUpdated(
   1198                         remote_change_handler_.ChangesSize()));
   1199 
   1200   MaybeStartFetchChanges();
   1201 }
   1202 
   1203 void DriveFileSyncService::NotifyLastOperationStatus(
   1204     SyncStatusCode sync_status,
   1205     bool used_network) {
   1206   UpdateServiceStateFromLastOperationStatus(sync_status, last_gdata_error_);
   1207 }
   1208 
   1209 // static
   1210 std::string DriveFileSyncService::PathToTitle(const base::FilePath& path) {
   1211   if (!IsSyncFSDirectoryOperationEnabled())
   1212     return path.AsUTF8Unsafe();
   1213 
   1214   return fileapi::FilePathToString(
   1215       base::FilePath(fileapi::VirtualPath::GetNormalizedFilePath(path)));
   1216 }
   1217 
   1218 // static
   1219 base::FilePath DriveFileSyncService::TitleToPath(const std::string& title) {
   1220   if (!IsSyncFSDirectoryOperationEnabled())
   1221     return base::FilePath::FromUTF8Unsafe(title);
   1222 
   1223   return fileapi::StringToFilePath(title).NormalizePathSeparators();
   1224 }
   1225 
   1226 // static
   1227 DriveMetadata::ResourceType
   1228 DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(
   1229     SyncFileType file_type) {
   1230   DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, file_type);
   1231   switch (file_type) {
   1232     case SYNC_FILE_TYPE_UNKNOWN:
   1233       return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE;
   1234     case SYNC_FILE_TYPE_FILE:
   1235       return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE;
   1236     case SYNC_FILE_TYPE_DIRECTORY:
   1237       return DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER;
   1238   }
   1239   NOTREACHED();
   1240   return DriveMetadata_ResourceType_RESOURCE_TYPE_FILE;
   1241 }
   1242 
   1243 // static
   1244 SyncFileType DriveFileSyncService::DriveMetadataResourceTypeToSyncFileType(
   1245     DriveMetadata::ResourceType resource_type) {
   1246   switch (resource_type) {
   1247     case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE:
   1248       return SYNC_FILE_TYPE_FILE;
   1249     case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER:
   1250       return SYNC_FILE_TYPE_DIRECTORY;
   1251   }
   1252   NOTREACHED();
   1253   return SYNC_FILE_TYPE_UNKNOWN;
   1254 }
   1255 
   1256 void DriveFileSyncService::FetchChangesForIncrementalSync(
   1257     const SyncStatusCallback& callback) {
   1258   DCHECK(may_have_unfetched_changes_);
   1259   DCHECK(pending_batch_sync_origins_.empty());
   1260   DCHECK(!metadata_store_->incremental_sync_origins().empty());
   1261 
   1262   DVLOG(1) << "FetchChangesForIncrementalSync (start_changestamp:"
   1263            << (largest_fetched_changestamp_ + 1) << ")";
   1264 
   1265   api_util_->ListChanges(
   1266       largest_fetched_changestamp_ + 1,
   1267       base::Bind(&DriveFileSyncService::DidFetchChangesForIncrementalSync,
   1268                  AsWeakPtr(),
   1269                  callback,
   1270                  false));
   1271 
   1272   may_have_unfetched_changes_ = false;
   1273 }
   1274 
   1275 void DriveFileSyncService::DidFetchChangesForIncrementalSync(
   1276     const SyncStatusCallback& callback,
   1277     bool has_new_changes,
   1278     google_apis::GDataErrorCode error,
   1279     scoped_ptr<google_apis::ResourceList> changes) {
   1280   if (error != google_apis::HTTP_SUCCESS) {
   1281     callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
   1282     return;
   1283   }
   1284 
   1285   bool reset_sync_root = false;
   1286   std::set<GURL> reset_origins;
   1287 
   1288   typedef ScopedVector<google_apis::ResourceEntry>::const_iterator iterator;
   1289   for (iterator itr = changes->entries().begin();
   1290        itr != changes->entries().end(); ++itr) {
   1291     const google_apis::ResourceEntry& entry = **itr;
   1292 
   1293     if (entry.deleted()) {
   1294       // Check if the sync root or origin root folder is deleted.
   1295       // (We reset resource_id after the for loop so that we can handle
   1296       // recursive delete for the origin (at least in this feed)
   1297       // while GetOriginForEntry for the origin still works.)
   1298       if (entry.resource_id() == sync_root_resource_id()) {
   1299         reset_sync_root = true;
   1300         continue;
   1301       }
   1302       GURL origin;
   1303       if (metadata_store_->GetOriginByOriginRootDirectoryId(
   1304               entry.resource_id(), &origin)) {
   1305         reset_origins.insert(origin);
   1306         continue;
   1307       }
   1308     }
   1309 
   1310     GURL origin;
   1311     if (!GetOriginForEntry(entry, &origin))
   1312       continue;
   1313 
   1314     DVLOG(3) << " * change:" << entry.title()
   1315              << (entry.deleted() ? " (deleted)" : " ")
   1316              << "[" << origin.spec() << "]";
   1317     has_new_changes = AppendRemoteChange(
   1318         origin, entry, entry.changestamp()) || has_new_changes;
   1319   }
   1320 
   1321   if (reset_sync_root) {
   1322     util::Log(logging::LOG_WARNING,
   1323               FROM_HERE,
   1324               "Detected unexpected SyncRoot deletion.");
   1325     metadata_store_->SetSyncRootDirectory(std::string());
   1326   }
   1327   for (std::set<GURL>::iterator itr = reset_origins.begin();
   1328        itr != reset_origins.end(); ++itr) {
   1329     util::Log(logging::LOG_WARNING,
   1330               FROM_HERE,
   1331               "Detected unexpected OriginRoot deletion: %s",
   1332               itr->spec().c_str());
   1333     pending_batch_sync_origins_.erase(*itr);
   1334     metadata_store_->SetOriginRootDirectory(*itr, std::string());
   1335   }
   1336 
   1337   GURL next_feed;
   1338   if (changes->GetNextFeedURL(&next_feed))
   1339     may_have_unfetched_changes_ = true;
   1340 
   1341   if (!changes->entries().empty())
   1342     largest_fetched_changestamp_ = changes->entries().back()->changestamp();
   1343 
   1344   callback.Run(SYNC_STATUS_OK);
   1345 }
   1346 
   1347 bool DriveFileSyncService::GetOriginForEntry(
   1348     const google_apis::ResourceEntry& entry,
   1349     GURL* origin_out) {
   1350   typedef ScopedVector<google_apis::Link>::const_iterator iterator;
   1351   for (iterator itr = entry.links().begin();
   1352        itr != entry.links().end(); ++itr) {
   1353     if ((*itr)->type() != google_apis::Link::LINK_PARENT)
   1354       continue;
   1355 
   1356     std::string resource_id(
   1357         drive::util::ExtractResourceIdFromUrl((*itr)->href()));
   1358     if (resource_id.empty())
   1359       continue;
   1360 
   1361     GURL origin;
   1362     metadata_store_->GetOriginByOriginRootDirectoryId(resource_id, &origin);
   1363     if (!origin.is_valid() || !metadata_store_->IsIncrementalSyncOrigin(origin))
   1364       continue;
   1365 
   1366     *origin_out = origin;
   1367     return true;
   1368   }
   1369   return false;
   1370 }
   1371 
   1372 void DriveFileSyncService::NotifyObserversFileStatusChanged(
   1373     const FileSystemURL& url,
   1374     SyncFileStatus sync_status,
   1375     SyncAction action_taken,
   1376     SyncDirection direction) {
   1377   if (sync_status != SYNC_FILE_STATUS_SYNCED) {
   1378     DCHECK_EQ(SYNC_ACTION_NONE, action_taken);
   1379     DCHECK_EQ(SYNC_DIRECTION_NONE, direction);
   1380   }
   1381 
   1382   FOR_EACH_OBSERVER(
   1383       FileStatusObserver, file_status_observers_,
   1384       OnFileStatusChanged(url, sync_status, action_taken, direction));
   1385 }
   1386 
   1387 void DriveFileSyncService::EnsureSyncRootDirectory(
   1388     const ResourceIdCallback& callback) {
   1389   if (!sync_root_resource_id().empty()) {
   1390     callback.Run(SYNC_STATUS_OK, sync_root_resource_id());
   1391     return;
   1392   }
   1393 
   1394   api_util_->GetDriveDirectoryForSyncRoot(base::Bind(
   1395       &DriveFileSyncService::DidEnsureSyncRoot, AsWeakPtr(), callback));
   1396 }
   1397 
   1398 void DriveFileSyncService::DidEnsureSyncRoot(
   1399     const ResourceIdCallback& callback,
   1400     google_apis::GDataErrorCode error,
   1401     const std::string& sync_root_resource_id) {
   1402   SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
   1403   if (status == SYNC_STATUS_OK)
   1404     metadata_store_->SetSyncRootDirectory(sync_root_resource_id);
   1405   callback.Run(status, sync_root_resource_id);
   1406 }
   1407 
   1408 void DriveFileSyncService::EnsureOriginRootDirectory(
   1409     const GURL& origin,
   1410     const ResourceIdCallback& callback) {
   1411   std::string resource_id = metadata_store_->GetResourceIdForOrigin(origin);
   1412   if (!resource_id.empty()) {
   1413     callback.Run(SYNC_STATUS_OK, resource_id);
   1414     return;
   1415   }
   1416 
   1417   EnsureSyncRootDirectory(base::Bind(
   1418       &DriveFileSyncService::DidEnsureSyncRootForOriginRoot,
   1419       AsWeakPtr(), origin, callback));
   1420 }
   1421 
   1422 void DriveFileSyncService::DidEnsureSyncRootForOriginRoot(
   1423     const GURL& origin,
   1424     const ResourceIdCallback& callback,
   1425     SyncStatusCode status,
   1426     const std::string& sync_root_resource_id) {
   1427   if (status != SYNC_STATUS_OK) {
   1428     callback.Run(status, std::string());
   1429     return;
   1430   }
   1431 
   1432   api_util_->GetDriveDirectoryForOrigin(
   1433       sync_root_resource_id,
   1434       origin,
   1435       base::Bind(&DriveFileSyncService::DidEnsureOriginRoot,
   1436                  AsWeakPtr(),
   1437                  origin,
   1438                  callback));
   1439 }
   1440 
   1441 void DriveFileSyncService::DidEnsureOriginRoot(
   1442     const GURL& origin,
   1443     const ResourceIdCallback& callback,
   1444     google_apis::GDataErrorCode error,
   1445     const std::string& resource_id) {
   1446   SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
   1447   if (status == SYNC_STATUS_OK &&
   1448       metadata_store_->IsKnownOrigin(origin)) {
   1449     metadata_store_->SetOriginRootDirectory(origin, resource_id);
   1450   }
   1451   callback.Run(status, resource_id);
   1452 }
   1453 
   1454 std::string DriveFileSyncService::sync_root_resource_id() {
   1455   return metadata_store_->sync_root_directory();
   1456 }
   1457 
   1458 }  // namespace sync_file_system
   1459