• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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/sync_file_system_service.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/format_macros.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/metrics/histogram.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
18 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/sync/profile_sync_service.h"
21 #include "chrome/browser/sync/profile_sync_service_factory.h"
22 #include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
23 #include "chrome/browser/sync_file_system/logger.h"
24 #include "chrome/browser/sync_file_system/sync_direction.h"
25 #include "chrome/browser/sync_file_system/sync_event_observer.h"
26 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
27 #include "chrome/browser/sync_file_system/sync_process_runner.h"
28 #include "chrome/browser/sync_file_system/sync_status_code.h"
29 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
30 #include "components/keyed_service/content/browser_context_dependency_manager.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/storage_partition.h"
33 #include "extensions/browser/extension_prefs.h"
34 #include "extensions/browser/extension_registry.h"
35 #include "extensions/common/extension.h"
36 #include "extensions/common/manifest_constants.h"
37 #include "storage/browser/fileapi/file_system_context.h"
38 #include "url/gurl.h"
39 
40 using content::BrowserThread;
41 using extensions::Extension;
42 using extensions::ExtensionPrefs;
43 using extensions::ExtensionRegistry;
44 using storage::FileSystemURL;
45 using storage::FileSystemURLSet;
46 
47 namespace sync_file_system {
48 
49 namespace {
50 
51 const char kLocalSyncName[] = "Local sync";
52 const char kRemoteSyncName[] = "Remote sync";
53 
RemoteStateToSyncServiceState(RemoteServiceState state)54 SyncServiceState RemoteStateToSyncServiceState(
55     RemoteServiceState state) {
56   switch (state) {
57     case REMOTE_SERVICE_OK:
58       return SYNC_SERVICE_RUNNING;
59     case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
60       return SYNC_SERVICE_TEMPORARY_UNAVAILABLE;
61     case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
62       return SYNC_SERVICE_AUTHENTICATION_REQUIRED;
63     case REMOTE_SERVICE_ACCESS_FORBIDDEN:
64       return SYNC_SERVICE_TEMPORARY_UNAVAILABLE;
65     case REMOTE_SERVICE_DISABLED:
66       return SYNC_SERVICE_DISABLED;
67     case REMOTE_SERVICE_STATE_MAX:
68       NOTREACHED();
69   }
70   NOTREACHED() << "Unknown remote service state: " << state;
71   return SYNC_SERVICE_DISABLED;
72 }
73 
DidHandleUninstalledEvent(const GURL & origin,SyncStatusCode code)74 void DidHandleUninstalledEvent(const GURL& origin, SyncStatusCode code) {
75   if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) {
76     util::Log(logging::LOG_WARNING, FROM_HERE,
77               "Failed to uninstall origin for uninstall event: %s",
78               origin.spec().c_str());
79   }
80 }
81 
DidHandleUnloadedEvent(const GURL & origin,SyncStatusCode code)82 void DidHandleUnloadedEvent(const GURL& origin, SyncStatusCode code) {
83   if (code != SYNC_STATUS_OK && code != SYNC_STATUS_UNKNOWN_ORIGIN) {
84     util::Log(logging::LOG_WARNING, FROM_HERE,
85               "Failed to disable origin for unload event: %s",
86               origin.spec().c_str());
87   }
88 }
89 
DidHandleLoadEvent(const GURL & origin,SyncStatusCode code)90 void DidHandleLoadEvent(
91     const GURL& origin,
92     SyncStatusCode code) {
93   if (code != SYNC_STATUS_OK) {
94     util::Log(logging::LOG_WARNING, FROM_HERE,
95               "Failed to enable origin for load event: %s",
96               origin.spec().c_str());
97   }
98 }
99 
SyncFileStatusToString(SyncFileStatus sync_file_status)100 std::string SyncFileStatusToString(SyncFileStatus sync_file_status) {
101   return extensions::api::sync_file_system::ToString(
102       extensions::SyncFileStatusToExtensionEnum(sync_file_status));
103 }
104 
105 // Gets called repeatedly until every SyncFileStatus has been mapped.
DidGetFileSyncStatusForDump(base::ListValue * files,size_t * num_results,const SyncFileSystemService::DumpFilesCallback & callback,base::DictionaryValue * file,SyncStatusCode sync_status_code,SyncFileStatus sync_file_status)106 void DidGetFileSyncStatusForDump(
107     base::ListValue* files,
108     size_t* num_results,
109     const SyncFileSystemService::DumpFilesCallback& callback,
110     base::DictionaryValue* file,
111     SyncStatusCode sync_status_code,
112     SyncFileStatus sync_file_status) {
113   DCHECK(files);
114   DCHECK(num_results);
115 
116   if (file)
117     file->SetString("status", SyncFileStatusToString(sync_file_status));
118 
119   // Once all results have been received, run the callback to signal end.
120   DCHECK_LE(*num_results, files->GetSize());
121   if (++*num_results < files->GetSize())
122     return;
123 
124   callback.Run(*files);
125 }
126 
127 // We need this indirection because WeakPtr can only be bound to methods
128 // without a return value.
GetLocalChangeProcessorAdapter(base::WeakPtr<SyncFileSystemService> service,const GURL & origin)129 LocalChangeProcessor* GetLocalChangeProcessorAdapter(
130     base::WeakPtr<SyncFileSystemService> service,
131     const GURL& origin) {
132   if (!service)
133     return NULL;
134   return service->GetLocalChangeProcessor(origin);
135 }
136 
137 }  // namespace
138 
139 //---------------------------------------------------------------------------
140 // SyncProcessRunner's.
141 
142 // SyncProcessRunner implementation for LocalSync.
143 class LocalSyncRunner : public SyncProcessRunner,
144                         public LocalFileSyncService::Observer {
145  public:
LocalSyncRunner(const std::string & name,SyncFileSystemService * sync_service)146   LocalSyncRunner(const std::string& name,
147                   SyncFileSystemService* sync_service)
148       : SyncProcessRunner(name, sync_service,
149                           scoped_ptr<SyncProcessRunner::TimerHelper>(), 1),
150         factory_(this) {}
151 
StartSync(const SyncStatusCallback & callback)152   virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE {
153     GetSyncService()->local_service_->ProcessLocalChange(
154         base::Bind(&LocalSyncRunner::DidProcessLocalChange,
155                    factory_.GetWeakPtr(), callback));
156   }
157 
158   // LocalFileSyncService::Observer overrides.
OnLocalChangeAvailable(int64 pending_changes)159   virtual void OnLocalChangeAvailable(int64 pending_changes) OVERRIDE {
160     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
161 
162     OnChangesUpdated(pending_changes);
163 
164     // Kick other sync runners just in case they're not running.
165     GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
166   }
167 
168  private:
DidProcessLocalChange(const SyncStatusCallback & callback,SyncStatusCode status,const FileSystemURL & url)169   void DidProcessLocalChange(
170       const SyncStatusCallback& callback,
171       SyncStatusCode status,
172       const FileSystemURL& url) {
173     util::Log(logging::LOG_VERBOSE, FROM_HERE,
174               "ProcessLocalChange finished with status=%d (%s) for url=%s",
175               status, SyncStatusCodeToString(status),
176               url.DebugString().c_str());
177     callback.Run(status);
178   }
179 
180   base::WeakPtrFactory<LocalSyncRunner> factory_;
181   DISALLOW_COPY_AND_ASSIGN(LocalSyncRunner);
182 };
183 
184 // SyncProcessRunner implementation for RemoteSync.
185 class RemoteSyncRunner : public SyncProcessRunner,
186                          public RemoteFileSyncService::Observer {
187  public:
RemoteSyncRunner(const std::string & name,SyncFileSystemService * sync_service,RemoteFileSyncService * remote_service)188   RemoteSyncRunner(const std::string& name,
189                    SyncFileSystemService* sync_service,
190                    RemoteFileSyncService* remote_service)
191       : SyncProcessRunner(name, sync_service,
192                           scoped_ptr<SyncProcessRunner::TimerHelper>(), 1),
193         remote_service_(remote_service),
194         last_state_(REMOTE_SERVICE_OK),
195         factory_(this) {}
196 
StartSync(const SyncStatusCallback & callback)197   virtual void StartSync(const SyncStatusCallback& callback) OVERRIDE {
198     remote_service_->ProcessRemoteChange(
199         base::Bind(&RemoteSyncRunner::DidProcessRemoteChange,
200                    factory_.GetWeakPtr(), callback));
201   }
202 
GetServiceState()203   virtual SyncServiceState GetServiceState() OVERRIDE {
204     return RemoteStateToSyncServiceState(last_state_);
205   }
206 
207   // RemoteFileSyncService::Observer overrides.
OnRemoteChangeQueueUpdated(int64 pending_changes)208   virtual void OnRemoteChangeQueueUpdated(int64 pending_changes) OVERRIDE {
209     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
210 
211     OnChangesUpdated(pending_changes);
212 
213     // Kick other sync runners just in case they're not running.
214     GetSyncService()->RunForEachSyncRunners(&SyncProcessRunner::Schedule);
215   }
216 
OnRemoteServiceStateUpdated(RemoteServiceState state,const std::string & description)217   virtual void OnRemoteServiceStateUpdated(
218       RemoteServiceState state,
219       const std::string& description) OVERRIDE {
220     // Just forward to SyncFileSystemService.
221     GetSyncService()->OnRemoteServiceStateUpdated(state, description);
222     last_state_ = state;
223   }
224 
225  private:
DidProcessRemoteChange(const SyncStatusCallback & callback,SyncStatusCode status,const FileSystemURL & url)226   void DidProcessRemoteChange(
227       const SyncStatusCallback& callback,
228       SyncStatusCode status,
229       const FileSystemURL& url) {
230     util::Log(logging::LOG_VERBOSE, FROM_HERE,
231               "ProcessRemoteChange finished with status=%d (%s) for url=%s",
232               status, SyncStatusCodeToString(status),
233               url.DebugString().c_str());
234 
235     if (status == SYNC_STATUS_FILE_BUSY) {
236       GetSyncService()->local_service_->RegisterURLForWaitingSync(
237           url, base::Bind(&RemoteSyncRunner::Schedule,
238                           factory_.GetWeakPtr()));
239     }
240     callback.Run(status);
241   }
242 
243   RemoteFileSyncService* remote_service_;
244   RemoteServiceState last_state_;
245   base::WeakPtrFactory<RemoteSyncRunner> factory_;
246   DISALLOW_COPY_AND_ASSIGN(RemoteSyncRunner);
247 };
248 
249 //-----------------------------------------------------------------------------
250 // SyncFileSystemService
251 
Shutdown()252 void SyncFileSystemService::Shutdown() {
253   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
254 
255   local_sync_runners_.clear();
256   remote_sync_runners_.clear();
257 
258   local_service_->Shutdown();
259   local_service_.reset();
260 
261   remote_service_.reset();
262 
263   ProfileSyncServiceBase* profile_sync_service =
264       ProfileSyncServiceFactory::GetForProfile(profile_);
265   if (profile_sync_service)
266     profile_sync_service->RemoveObserver(this);
267 
268   ExtensionRegistry::Get(profile_)->RemoveObserver(this);
269 
270   profile_ = NULL;
271 }
272 
~SyncFileSystemService()273 SyncFileSystemService::~SyncFileSystemService() {
274   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
275   DCHECK(!profile_);
276 }
277 
InitializeForApp(storage::FileSystemContext * file_system_context,const GURL & app_origin,const SyncStatusCallback & callback)278 void SyncFileSystemService::InitializeForApp(
279     storage::FileSystemContext* file_system_context,
280     const GURL& app_origin,
281     const SyncStatusCallback& callback) {
282   DCHECK(local_service_);
283   DCHECK(remote_service_);
284   DCHECK(app_origin == app_origin.GetOrigin());
285 
286   util::Log(logging::LOG_VERBOSE, FROM_HERE,
287             "Initializing for App: %s", app_origin.spec().c_str());
288 
289   local_service_->MaybeInitializeFileSystemContext(
290       app_origin, file_system_context,
291       base::Bind(&SyncFileSystemService::DidInitializeFileSystem,
292                  AsWeakPtr(), app_origin, callback));
293 }
294 
GetExtensionStatusMap(const ExtensionStatusMapCallback & callback)295 void SyncFileSystemService::GetExtensionStatusMap(
296     const ExtensionStatusMapCallback& callback) {
297   remote_service_->GetOriginStatusMap(
298       base::Bind(&SyncFileSystemService::DidGetExtensionStatusMap,
299                  AsWeakPtr(), callback));
300 }
301 
DumpFiles(const GURL & origin,const DumpFilesCallback & callback)302 void SyncFileSystemService::DumpFiles(const GURL& origin,
303                                       const DumpFilesCallback& callback) {
304   DCHECK(!origin.is_empty());
305 
306   content::StoragePartition* storage_partition =
307       content::BrowserContext::GetStoragePartitionForSite(profile_, origin);
308   storage::FileSystemContext* file_system_context =
309       storage_partition->GetFileSystemContext();
310   local_service_->MaybeInitializeFileSystemContext(
311       origin, file_system_context,
312       base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump,
313                  AsWeakPtr(), origin, callback));
314 }
315 
DumpDatabase(const DumpFilesCallback & callback)316 void SyncFileSystemService::DumpDatabase(const DumpFilesCallback& callback) {
317   remote_service_->DumpDatabase(
318       base::Bind(&SyncFileSystemService::DidDumpDatabase,
319                  AsWeakPtr(), callback));
320 }
321 
GetFileSyncStatus(const FileSystemURL & url,const SyncFileStatusCallback & callback)322 void SyncFileSystemService::GetFileSyncStatus(
323     const FileSystemURL& url, const SyncFileStatusCallback& callback) {
324   DCHECK(local_service_);
325   DCHECK(GetRemoteService(url.origin()));
326 
327   // It's possible to get an invalid FileEntry.
328   if (!url.is_valid()) {
329     base::ThreadTaskRunnerHandle::Get()->PostTask(
330         FROM_HERE,
331         base::Bind(callback,
332                    SYNC_FILE_ERROR_INVALID_URL,
333                    SYNC_FILE_STATUS_UNKNOWN));
334     return;
335   }
336 
337   local_service_->HasPendingLocalChanges(
338       url,
339       base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus,
340                  AsWeakPtr(), callback));
341 }
342 
AddSyncEventObserver(SyncEventObserver * observer)343 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) {
344   observers_.AddObserver(observer);
345 }
346 
RemoveSyncEventObserver(SyncEventObserver * observer)347 void SyncFileSystemService::RemoveSyncEventObserver(
348     SyncEventObserver* observer) {
349   observers_.RemoveObserver(observer);
350 }
351 
GetLocalChangeProcessor(const GURL & origin)352 LocalChangeProcessor* SyncFileSystemService::GetLocalChangeProcessor(
353     const GURL& origin) {
354   return GetRemoteService(origin)->GetLocalChangeProcessor();
355 }
356 
OnSyncIdle()357 void SyncFileSystemService::OnSyncIdle() {
358   if (promoting_demoted_changes_)
359     return;
360   promoting_demoted_changes_ = true;
361 
362   int* job_count = new int(1);
363   base::Closure promote_completion_callback =
364       base::Bind(&SyncFileSystemService::OnPromotionCompleted,
365                  AsWeakPtr(), base::Owned(job_count));
366 
367   int64 remote_changes = 0;
368   for (size_t i = 0; i < remote_sync_runners_.size(); ++i)
369     remote_changes += remote_sync_runners_[i]->pending_changes();
370   if (remote_changes == 0) {
371     ++*job_count;
372     local_service_->PromoteDemotedChanges(promote_completion_callback);
373   }
374 
375   int64 local_changes = 0;
376   for (size_t i = 0; i < local_sync_runners_.size(); ++i)
377     local_changes += local_sync_runners_[i]->pending_changes();
378   if (local_changes == 0) {
379     ++*job_count;
380     remote_service_->PromoteDemotedChanges(promote_completion_callback);
381   }
382 
383   promote_completion_callback.Run();
384 }
385 
OnPromotionCompleted(int * count)386 void SyncFileSystemService::OnPromotionCompleted(int* count) {
387   if (--*count != 0)
388     return;
389   promoting_demoted_changes_ = false;
390   CheckIfIdle();
391 }
392 
CheckIfIdle()393 void SyncFileSystemService::CheckIfIdle() {
394   if (promoting_demoted_changes_)
395     return;
396 
397   for (size_t i = 0; i < remote_sync_runners_.size(); ++i) {
398     SyncServiceState service_state = remote_sync_runners_[i]->GetServiceState();
399     if (service_state != SYNC_SERVICE_RUNNING)
400       continue;
401 
402     if (remote_sync_runners_[i]->pending_changes())
403       return;
404   }
405 
406   for (size_t i = 0; i < local_sync_runners_.size(); ++i) {
407     SyncServiceState service_state = local_sync_runners_[i]->GetServiceState();
408     if (service_state != SYNC_SERVICE_RUNNING)
409       continue;
410 
411     if (local_sync_runners_[i]->pending_changes())
412       return;
413   }
414 
415   if (idle_callback_.is_null())
416     return;
417 
418   base::Closure callback = idle_callback_;
419   idle_callback_.Reset();
420   callback.Run();
421 }
422 
GetSyncServiceState()423 SyncServiceState SyncFileSystemService::GetSyncServiceState() {
424   // For now we always query the state from the main RemoteFileSyncService.
425   return RemoteStateToSyncServiceState(remote_service_->GetCurrentState());
426 }
427 
GetSyncService()428 SyncFileSystemService* SyncFileSystemService::GetSyncService() {
429   return this;
430 }
431 
CallOnIdleForTesting(const base::Closure & callback)432 void SyncFileSystemService::CallOnIdleForTesting(
433     const base::Closure& callback) {
434   DCHECK(idle_callback_.is_null());
435   idle_callback_ = callback;
436   CheckIfIdle();
437 }
438 
SyncFileSystemService(Profile * profile)439 SyncFileSystemService::SyncFileSystemService(Profile* profile)
440     : profile_(profile),
441       sync_enabled_(true),
442       promoting_demoted_changes_(false) {
443 }
444 
Initialize(scoped_ptr<LocalFileSyncService> local_service,scoped_ptr<RemoteFileSyncService> remote_service)445 void SyncFileSystemService::Initialize(
446     scoped_ptr<LocalFileSyncService> local_service,
447     scoped_ptr<RemoteFileSyncService> remote_service) {
448   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
449   DCHECK(local_service);
450   DCHECK(remote_service);
451   DCHECK(profile_);
452 
453   local_service_ = local_service.Pass();
454   remote_service_ = remote_service.Pass();
455 
456   scoped_ptr<LocalSyncRunner> local_syncer(
457       new LocalSyncRunner(kLocalSyncName, this));
458   scoped_ptr<RemoteSyncRunner> remote_syncer(
459       new RemoteSyncRunner(kRemoteSyncName, this, remote_service_.get()));
460 
461   local_service_->AddChangeObserver(local_syncer.get());
462   local_service_->SetLocalChangeProcessorCallback(
463       base::Bind(&GetLocalChangeProcessorAdapter, AsWeakPtr()));
464 
465   remote_service_->AddServiceObserver(remote_syncer.get());
466   remote_service_->AddFileStatusObserver(this);
467   remote_service_->SetRemoteChangeProcessor(local_service_.get());
468 
469   local_sync_runners_.push_back(local_syncer.release());
470   remote_sync_runners_.push_back(remote_syncer.release());
471 
472   ProfileSyncServiceBase* profile_sync_service =
473       ProfileSyncServiceFactory::GetForProfile(profile_);
474   if (profile_sync_service) {
475     UpdateSyncEnabledStatus(profile_sync_service);
476     profile_sync_service->AddObserver(this);
477   }
478 
479   ExtensionRegistry::Get(profile_)->AddObserver(this);
480 }
481 
DidInitializeFileSystem(const GURL & app_origin,const SyncStatusCallback & callback,SyncStatusCode status)482 void SyncFileSystemService::DidInitializeFileSystem(
483     const GURL& app_origin,
484     const SyncStatusCallback& callback,
485     SyncStatusCode status) {
486   DVLOG(1) << "DidInitializeFileSystem: "
487            << app_origin.spec() << " " << status;
488 
489   if (status != SYNC_STATUS_OK) {
490     callback.Run(status);
491     return;
492   }
493 
494   // Local side of initialization for the app is done.
495   // Continue on initializing the remote side.
496   GetRemoteService(app_origin)->RegisterOrigin(
497       app_origin,
498       base::Bind(&SyncFileSystemService::DidRegisterOrigin,
499                  AsWeakPtr(), app_origin, callback));
500 }
501 
DidRegisterOrigin(const GURL & app_origin,const SyncStatusCallback & callback,SyncStatusCode status)502 void SyncFileSystemService::DidRegisterOrigin(
503     const GURL& app_origin,
504     const SyncStatusCallback& callback,
505     SyncStatusCode status) {
506   util::Log(logging::LOG_VERBOSE, FROM_HERE,
507             "DidInitializeForApp (registered the origin): %s: %s",
508             app_origin.spec().c_str(),
509             SyncStatusCodeToString(status));
510 
511   UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult",
512                             GetRemoteService(app_origin)->GetCurrentState(),
513                             REMOTE_SERVICE_STATE_MAX);
514 
515   if (status == SYNC_STATUS_FAILED) {
516     // If we got generic error return the service status information.
517     switch (GetRemoteService(app_origin)->GetCurrentState()) {
518       case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
519         callback.Run(SYNC_STATUS_AUTHENTICATION_FAILED);
520         return;
521       case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
522         callback.Run(SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE);
523         return;
524       default:
525         break;
526     }
527   }
528 
529   callback.Run(status);
530 }
531 
DidInitializeFileSystemForDump(const GURL & origin,const DumpFilesCallback & callback,SyncStatusCode status)532 void SyncFileSystemService::DidInitializeFileSystemForDump(
533     const GURL& origin,
534     const DumpFilesCallback& callback,
535     SyncStatusCode status) {
536   DCHECK(!origin.is_empty());
537 
538   if (status != SYNC_STATUS_OK) {
539     callback.Run(base::ListValue());
540     return;
541   }
542 
543   GetRemoteService(origin)->DumpFiles(
544       origin,
545       base::Bind(
546           &SyncFileSystemService::DidDumpFiles,
547           AsWeakPtr(),
548           origin,
549           callback));
550 }
551 
DidDumpFiles(const GURL & origin,const DumpFilesCallback & callback,scoped_ptr<base::ListValue> dump_files)552 void SyncFileSystemService::DidDumpFiles(
553     const GURL& origin,
554     const DumpFilesCallback& callback,
555     scoped_ptr<base::ListValue> dump_files) {
556   if (!dump_files || !dump_files->GetSize()) {
557     callback.Run(base::ListValue());
558     return;
559   }
560 
561   base::ListValue* files = dump_files.get();
562   base::Callback<void(base::DictionaryValue*,
563                       SyncStatusCode,
564                       SyncFileStatus)> completion_callback =
565       base::Bind(&DidGetFileSyncStatusForDump,
566                  base::Owned(dump_files.release()),
567                  base::Owned(new size_t(0)),
568                  callback);
569 
570   // After all metadata loaded, sync status can be added to each entry.
571   for (size_t i = 0; i < files->GetSize(); ++i) {
572     base::DictionaryValue* file = NULL;
573     std::string path_string;
574     if (!files->GetDictionary(i, &file) ||
575         !file->GetString("path", &path_string)) {
576       NOTREACHED();
577       completion_callback.Run(
578           NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
579       continue;
580     }
581 
582     base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string);
583     FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path);
584     GetFileSyncStatus(url, base::Bind(completion_callback, file));
585   }
586 }
587 
DidDumpDatabase(const DumpFilesCallback & callback,scoped_ptr<base::ListValue> list)588 void SyncFileSystemService::DidDumpDatabase(const DumpFilesCallback& callback,
589                                             scoped_ptr<base::ListValue> list) {
590   if (!list)
591     list = make_scoped_ptr(new base::ListValue);
592   callback.Run(*list);
593 }
594 
DidGetExtensionStatusMap(const ExtensionStatusMapCallback & callback,scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map)595 void SyncFileSystemService::DidGetExtensionStatusMap(
596     const ExtensionStatusMapCallback& callback,
597     scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map) {
598   if (!status_map)
599     status_map = make_scoped_ptr(new RemoteFileSyncService::OriginStatusMap);
600   callback.Run(*status_map);
601 }
602 
SetSyncEnabledForTesting(bool enabled)603 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) {
604   sync_enabled_ = enabled;
605   remote_service_->SetSyncEnabled(sync_enabled_);
606 }
607 
DidGetLocalChangeStatus(const SyncFileStatusCallback & callback,SyncStatusCode status,bool has_pending_local_changes)608 void SyncFileSystemService::DidGetLocalChangeStatus(
609     const SyncFileStatusCallback& callback,
610     SyncStatusCode status,
611     bool has_pending_local_changes) {
612   callback.Run(
613       status,
614       has_pending_local_changes ?
615           SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED);
616 }
617 
OnRemoteServiceStateUpdated(RemoteServiceState state,const std::string & description)618 void SyncFileSystemService::OnRemoteServiceStateUpdated(
619     RemoteServiceState state,
620     const std::string& description) {
621   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
622   util::Log(logging::LOG_VERBOSE, FROM_HERE,
623             "OnRemoteServiceStateChanged: %d %s", state, description.c_str());
624 
625   FOR_EACH_OBSERVER(
626       SyncEventObserver, observers_,
627       OnSyncStateUpdated(GURL(),
628                          RemoteStateToSyncServiceState(state),
629                          description));
630 
631   RunForEachSyncRunners(&SyncProcessRunner::Schedule);
632 }
633 
OnExtensionInstalled(content::BrowserContext * browser_context,const Extension * extension,bool is_update)634 void SyncFileSystemService::OnExtensionInstalled(
635     content::BrowserContext* browser_context,
636     const Extension* extension,
637     bool is_update) {
638   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
639   DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin;
640   // NOTE: When an app is uninstalled and re-installed in a sequence,
641   // |local_service_| may still keeps |app_origin| as disabled origin.
642   local_service_->SetOriginEnabled(app_origin, true);
643 }
644 
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,extensions::UnloadedExtensionInfo::Reason reason)645 void SyncFileSystemService::OnExtensionUnloaded(
646     content::BrowserContext* browser_context,
647     const Extension* extension,
648     extensions::UnloadedExtensionInfo::Reason reason) {
649   if (reason != extensions::UnloadedExtensionInfo::REASON_DISABLE)
650     return;
651 
652   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
653   int disable_reasons =
654       ExtensionPrefs::Get(profile_)->GetDisableReasons(extension->id());
655   if (disable_reasons & Extension::DISABLE_RELOAD) {
656     // Bypass disabling the origin since the app will be re-enabled soon.
657     // NOTE: If re-enabling the app fails, the app is disabled while it is
658     // handled as enabled origin in the SyncFS. This should be safe and will be
659     // recovered when the user re-enables the app manually or the sync service
660     // restarts.
661     DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE_RELOAD): "
662              << app_origin;
663     return;
664   }
665 
666   DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
667            << app_origin;
668   GetRemoteService(app_origin)->DisableOrigin(
669       app_origin,
670       base::Bind(&DidHandleUnloadedEvent, app_origin));
671   local_service_->SetOriginEnabled(app_origin, false);
672 }
673 
OnExtensionUninstalled(content::BrowserContext * browser_context,const Extension * extension,extensions::UninstallReason reason)674 void SyncFileSystemService::OnExtensionUninstalled(
675     content::BrowserContext* browser_context,
676     const Extension* extension,
677     extensions::UninstallReason reason) {
678   RemoteFileSyncService::UninstallFlag flag =
679       RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE;
680   // If it's loaded from an unpacked package and with key: field,
681   // the uninstall will not be sync'ed and the user might be using the
682   // same app key in other installs, so avoid purging the remote folder.
683   if (extensions::Manifest::IsUnpackedLocation(extension->location()) &&
684       extension->manifest()->HasKey(extensions::manifest_keys::kKey)) {
685     flag = RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE;
686   }
687 
688   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
689   DVLOG(1) << "Handle extension notification for UNINSTALLED: "
690            << app_origin;
691   GetRemoteService(app_origin)->UninstallOrigin(
692       app_origin, flag,
693       base::Bind(&DidHandleUninstalledEvent, app_origin));
694   local_service_->SetOriginEnabled(app_origin, false);
695 }
696 
OnExtensionLoaded(content::BrowserContext * browser_context,const Extension * extension)697 void SyncFileSystemService::OnExtensionLoaded(
698     content::BrowserContext* browser_context,
699     const Extension* extension) {
700   GURL app_origin = Extension::GetBaseURLFromExtensionId(extension->id());
701   DVLOG(1) << "Handle extension notification for LOADED: " << app_origin;
702   GetRemoteService(app_origin)->EnableOrigin(
703       app_origin,
704       base::Bind(&DidHandleLoadEvent, app_origin));
705   local_service_->SetOriginEnabled(app_origin, true);
706 }
707 
OnStateChanged()708 void SyncFileSystemService::OnStateChanged() {
709   ProfileSyncServiceBase* profile_sync_service =
710       ProfileSyncServiceFactory::GetForProfile(profile_);
711   if (profile_sync_service)
712     UpdateSyncEnabledStatus(profile_sync_service);
713 }
714 
OnFileStatusChanged(const FileSystemURL & url,SyncFileStatus sync_status,SyncAction action_taken,SyncDirection direction)715 void SyncFileSystemService::OnFileStatusChanged(
716     const FileSystemURL& url,
717     SyncFileStatus sync_status,
718     SyncAction action_taken,
719     SyncDirection direction) {
720   FOR_EACH_OBSERVER(
721       SyncEventObserver, observers_,
722       OnFileSynced(url, sync_status, action_taken, direction));
723 }
724 
UpdateSyncEnabledStatus(ProfileSyncServiceBase * profile_sync_service)725 void SyncFileSystemService::UpdateSyncEnabledStatus(
726     ProfileSyncServiceBase* profile_sync_service) {
727   if (!profile_sync_service->HasSyncSetupCompleted())
728     return;
729   bool old_sync_enabled = sync_enabled_;
730   sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
731       syncer::APPS);
732   remote_service_->SetSyncEnabled(sync_enabled_);
733   if (!old_sync_enabled && sync_enabled_)
734     RunForEachSyncRunners(&SyncProcessRunner::Schedule);
735 }
736 
RunForEachSyncRunners(void (SyncProcessRunner::* method)())737 void SyncFileSystemService::RunForEachSyncRunners(
738     void(SyncProcessRunner::*method)()) {
739   for (ScopedVector<SyncProcessRunner>::iterator iter =
740            local_sync_runners_.begin();
741        iter != local_sync_runners_.end(); ++iter)
742     ((*iter)->*method)();
743   for (ScopedVector<SyncProcessRunner>::iterator iter =
744            remote_sync_runners_.begin();
745        iter != remote_sync_runners_.end(); ++iter)
746     ((*iter)->*method)();
747 }
748 
GetRemoteService(const GURL & origin)749 RemoteFileSyncService* SyncFileSystemService::GetRemoteService(
750     const GURL& origin) {
751   return remote_service_.get();
752 }
753 
754 }  // namespace sync_file_system
755