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