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