Home | History | Annotate | Download | only in sync_file_system
      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/stl_util.h"
     14 #include "chrome/browser/chrome_notification_types.h"
     15 #include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
     16 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/browser/sync/profile_sync_service.h"
     19 #include "chrome/browser/sync/profile_sync_service_factory.h"
     20 #include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.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_status_code.h"
     27 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     28 #include "chrome/common/extensions/extension.h"
     29 #include "components/browser_context_keyed_service/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 "url/gurl.h"
     35 #include "webkit/browser/fileapi/file_system_context.h"
     36 
     37 using content::BrowserThread;
     38 using fileapi::FileSystemURL;
     39 using fileapi::FileSystemURLSet;
     40 
     41 namespace sync_file_system {
     42 
     43 namespace {
     44 
     45 const int64 kRetryTimerIntervalInSeconds = 20 * 60;  // 20 min.
     46 
     47 SyncServiceState RemoteStateToSyncServiceState(
     48     RemoteServiceState state) {
     49   switch (state) {
     50     case REMOTE_SERVICE_OK:
     51       return SYNC_SERVICE_RUNNING;
     52     case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
     53       return SYNC_SERVICE_TEMPORARY_UNAVAILABLE;
     54     case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
     55       return SYNC_SERVICE_AUTHENTICATION_REQUIRED;
     56     case REMOTE_SERVICE_DISABLED:
     57       return SYNC_SERVICE_DISABLED;
     58   }
     59   NOTREACHED() << "Unknown remote service state: " << state;
     60   return SYNC_SERVICE_DISABLED;
     61 }
     62 
     63 void DidHandleOriginForExtensionUnloadedEvent(
     64     int type,
     65     const GURL& origin,
     66     SyncStatusCode code) {
     67   DCHECK(chrome::NOTIFICATION_EXTENSION_UNLOADED == type ||
     68          chrome::NOTIFICATION_EXTENSION_UNINSTALLED == type);
     69   if (code != SYNC_STATUS_OK &&
     70       code != SYNC_STATUS_UNKNOWN_ORIGIN) {
     71     switch (type) {
     72       case chrome::NOTIFICATION_EXTENSION_UNLOADED:
     73         util::Log(logging::LOG_WARNING,
     74                   FROM_HERE,
     75                   "Disabling origin for UNLOADED(DISABLE) failed: %s",
     76                   origin.spec().c_str());
     77         break;
     78       case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
     79         util::Log(logging::LOG_WARNING,
     80                   FROM_HERE,
     81                   "Uninstall origin for UNINSTALLED failed: %s",
     82                   origin.spec().c_str());
     83         break;
     84       default:
     85         break;
     86     }
     87   }
     88 }
     89 
     90 void DidHandleOriginForExtensionEnabledEvent(
     91     int type,
     92     const GURL& origin,
     93     SyncStatusCode code) {
     94   DCHECK(chrome::NOTIFICATION_EXTENSION_ENABLED == type);
     95   if (code != SYNC_STATUS_OK)
     96     util::Log(logging::LOG_WARNING,
     97               FROM_HERE,
     98               "Enabling origin for ENABLED failed: %s",
     99               origin.spec().c_str());
    100 }
    101 
    102 std::string SyncFileStatusToString(SyncFileStatus sync_file_status) {
    103   return extensions::api::sync_file_system::ToString(
    104       extensions::SyncFileStatusToExtensionEnum(sync_file_status));
    105 }
    106 
    107 // Gets called repeatedly until every SyncFileStatus has been mapped.
    108 void DidGetFileSyncStatusForDump(
    109     base::ListValue* files,
    110     size_t* num_results,
    111     const SyncFileSystemService::DumpFilesCallback& callback,
    112     base::DictionaryValue* file,
    113     SyncStatusCode sync_status_code,
    114     SyncFileStatus sync_file_status) {
    115   DCHECK(files);
    116   DCHECK(num_results);
    117 
    118   if (file)
    119     file->SetString("status", SyncFileStatusToString(sync_file_status));
    120 
    121   // Once all results have been received, run the callback to signal end.
    122   DCHECK_LE(*num_results, files->GetSize());
    123   if (++*num_results < files->GetSize())
    124     return;
    125 
    126   callback.Run(files);
    127 }
    128 
    129 }  // namespace
    130 
    131 void SyncFileSystemService::Shutdown() {
    132   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    133 
    134   local_file_service_->Shutdown();
    135   local_file_service_.reset();
    136 
    137   remote_file_service_.reset();
    138 
    139   ProfileSyncServiceBase* profile_sync_service =
    140       ProfileSyncServiceFactory::GetForProfile(profile_);
    141   if (profile_sync_service)
    142     profile_sync_service->RemoveObserver(this);
    143 
    144   profile_ = NULL;
    145 }
    146 
    147 SyncFileSystemService::~SyncFileSystemService() {
    148   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    149   DCHECK(!profile_);
    150 }
    151 
    152 void SyncFileSystemService::InitializeForApp(
    153     fileapi::FileSystemContext* file_system_context,
    154     const GURL& app_origin,
    155     const SyncStatusCallback& callback) {
    156   DCHECK(local_file_service_);
    157   DCHECK(remote_file_service_);
    158   DCHECK(app_origin == app_origin.GetOrigin());
    159 
    160   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    161             "Initializing for App: %s", app_origin.spec().c_str());
    162 
    163   local_file_service_->MaybeInitializeFileSystemContext(
    164       app_origin, file_system_context,
    165       base::Bind(&SyncFileSystemService::DidInitializeFileSystem,
    166                  AsWeakPtr(), app_origin, callback));
    167 }
    168 
    169 SyncServiceState SyncFileSystemService::GetSyncServiceState() {
    170   return RemoteStateToSyncServiceState(remote_file_service_->GetCurrentState());
    171 }
    172 
    173 void SyncFileSystemService::GetExtensionStatusMap(
    174     std::map<GURL, std::string>* status_map) {
    175   DCHECK(status_map);
    176   remote_file_service_->GetOriginStatusMap(status_map);
    177 }
    178 
    179 void SyncFileSystemService::DumpFiles(const GURL& origin,
    180                                       const DumpFilesCallback& callback) {
    181   DCHECK(!origin.is_empty());
    182 
    183   content::StoragePartition* storage_partition =
    184       content::BrowserContext::GetStoragePartitionForSite(profile_, origin);
    185   fileapi::FileSystemContext* file_system_context =
    186       storage_partition->GetFileSystemContext();
    187   local_file_service_->MaybeInitializeFileSystemContext(
    188       origin, file_system_context,
    189       base::Bind(&SyncFileSystemService::DidInitializeFileSystemForDump,
    190                  AsWeakPtr(), origin, callback));
    191 }
    192 
    193 void SyncFileSystemService::GetFileSyncStatus(
    194     const FileSystemURL& url, const SyncFileStatusCallback& callback) {
    195   DCHECK(local_file_service_);
    196   DCHECK(remote_file_service_);
    197 
    198   // It's possible to get an invalid FileEntry.
    199   if (!url.is_valid()) {
    200     base::MessageLoopProxy::current()->PostTask(
    201         FROM_HERE,
    202         base::Bind(callback,
    203                    SYNC_FILE_ERROR_INVALID_URL,
    204                    SYNC_FILE_STATUS_UNKNOWN));
    205     return;
    206   }
    207 
    208   if (remote_file_service_->IsConflicting(url)) {
    209     base::MessageLoopProxy::current()->PostTask(
    210         FROM_HERE,
    211         base::Bind(callback,
    212                    SYNC_STATUS_OK,
    213                    SYNC_FILE_STATUS_CONFLICTING));
    214     return;
    215   }
    216 
    217   local_file_service_->HasPendingLocalChanges(
    218       url,
    219       base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus,
    220                  AsWeakPtr(), callback));
    221 }
    222 
    223 void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) {
    224   observers_.AddObserver(observer);
    225 }
    226 
    227 void SyncFileSystemService::RemoveSyncEventObserver(
    228     SyncEventObserver* observer) {
    229   observers_.RemoveObserver(observer);
    230 }
    231 
    232 ConflictResolutionPolicy
    233 SyncFileSystemService::GetConflictResolutionPolicy() const {
    234   return remote_file_service_->GetConflictResolutionPolicy();
    235 }
    236 
    237 SyncStatusCode SyncFileSystemService::SetConflictResolutionPolicy(
    238     ConflictResolutionPolicy policy) {
    239   return remote_file_service_->SetConflictResolutionPolicy(policy);
    240 }
    241 
    242 SyncFileSystemService::SyncFileSystemService(Profile* profile)
    243     : profile_(profile),
    244       pending_local_changes_(0),
    245       pending_remote_changes_(0),
    246       local_sync_running_(false),
    247       remote_sync_running_(false),
    248       is_waiting_remote_sync_enabled_(false),
    249       sync_enabled_(true) {
    250 }
    251 
    252 void SyncFileSystemService::Initialize(
    253     scoped_ptr<LocalFileSyncService> local_file_service,
    254     scoped_ptr<RemoteFileSyncService> remote_file_service) {
    255   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    256   DCHECK(local_file_service);
    257   DCHECK(remote_file_service);
    258   DCHECK(profile_);
    259 
    260   local_file_service_ = local_file_service.Pass();
    261   remote_file_service_ = remote_file_service.Pass();
    262 
    263   local_file_service_->AddChangeObserver(this);
    264   local_file_service_->SetLocalChangeProcessor(
    265       remote_file_service_->GetLocalChangeProcessor());
    266 
    267   remote_file_service_->AddServiceObserver(this);
    268   remote_file_service_->AddFileStatusObserver(this);
    269   remote_file_service_->SetRemoteChangeProcessor(local_file_service_.get());
    270 
    271   ProfileSyncServiceBase* profile_sync_service =
    272       ProfileSyncServiceFactory::GetForProfile(profile_);
    273   if (profile_sync_service) {
    274     UpdateSyncEnabledStatus(profile_sync_service);
    275     profile_sync_service->AddObserver(this);
    276   }
    277 
    278   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
    279                  content::Source<Profile>(profile_));
    280   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
    281                  content::Source<Profile>(profile_));
    282   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
    283                  content::Source<Profile>(profile_));
    284   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED,
    285                  content::Source<Profile>(profile_));
    286 }
    287 
    288 void SyncFileSystemService::DidInitializeFileSystem(
    289     const GURL& app_origin,
    290     const SyncStatusCallback& callback,
    291     SyncStatusCode status) {
    292   DVLOG(1) << "DidInitializeFileSystem: "
    293            << app_origin.spec() << " " << status;
    294 
    295   if (status != SYNC_STATUS_OK) {
    296     callback.Run(status);
    297     return;
    298   }
    299 
    300   // Local side of initialization for the app is done.
    301   // Continue on initializing the remote side.
    302   remote_file_service_->RegisterOriginForTrackingChanges(
    303       app_origin,
    304       base::Bind(&SyncFileSystemService::DidRegisterOrigin,
    305                  AsWeakPtr(), app_origin, callback));
    306 }
    307 
    308 void SyncFileSystemService::DidRegisterOrigin(
    309     const GURL& app_origin,
    310     const SyncStatusCallback& callback,
    311     SyncStatusCode status) {
    312   DVLOG(1) << "DidRegisterOrigin: " << app_origin.spec() << " " << status;
    313 
    314   callback.Run(status);
    315 }
    316 
    317 void SyncFileSystemService::DidInitializeFileSystemForDump(
    318     const GURL& origin,
    319     const DumpFilesCallback& callback,
    320     SyncStatusCode status) {
    321   DCHECK(!origin.is_empty());
    322 
    323   if (status != SYNC_STATUS_OK) {
    324     base::ListValue empty_result;
    325     callback.Run(&empty_result);
    326     return;
    327   }
    328 
    329   base::ListValue* files = remote_file_service_->DumpFiles(origin).release();
    330   if (!files->GetSize()) {
    331     callback.Run(files);
    332     return;
    333   }
    334 
    335   base::Callback<void(base::DictionaryValue* file,
    336                       SyncStatusCode sync_status,
    337                       SyncFileStatus sync_file_status)> completion_callback =
    338       base::Bind(&DidGetFileSyncStatusForDump, base::Owned(files),
    339                  base::Owned(new size_t(0)), callback);
    340 
    341   // After all metadata loaded, sync status can be added to each entry.
    342   for (size_t i = 0; i < files->GetSize(); ++i) {
    343     base::DictionaryValue* file = NULL;
    344     std::string path_string;
    345     if (!files->GetDictionary(i, &file) ||
    346         !file->GetString("path", &path_string)) {
    347       NOTREACHED();
    348       completion_callback.Run(
    349           NULL, SYNC_FILE_ERROR_FAILED, SYNC_FILE_STATUS_UNKNOWN);
    350       continue;
    351     }
    352 
    353     base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path_string);
    354     FileSystemURL url = CreateSyncableFileSystemURL(origin, file_path);
    355     GetFileSyncStatus(url, base::Bind(completion_callback, file));
    356   }
    357 }
    358 
    359 void SyncFileSystemService::SetSyncEnabledForTesting(bool enabled) {
    360   sync_enabled_ = enabled;
    361   remote_file_service_->SetSyncEnabled(sync_enabled_);
    362 }
    363 
    364 void SyncFileSystemService::MaybeStartSync() {
    365   if (!profile_ || !sync_enabled_)
    366     return;
    367 
    368   if (pending_local_changes_ + pending_remote_changes_ == 0)
    369     return;
    370 
    371   DVLOG(2) << "MaybeStartSync() called (remote service state:"
    372            << remote_file_service_->GetCurrentState() << ")";
    373   switch (remote_file_service_->GetCurrentState()) {
    374     case REMOTE_SERVICE_OK:
    375       break;
    376 
    377     case REMOTE_SERVICE_TEMPORARY_UNAVAILABLE:
    378       if (sync_retry_timer_.IsRunning())
    379         return;
    380       sync_retry_timer_.Start(
    381           FROM_HERE,
    382           base::TimeDelta::FromSeconds(kRetryTimerIntervalInSeconds),
    383           this, &SyncFileSystemService::MaybeStartSync);
    384       break;
    385 
    386     case REMOTE_SERVICE_AUTHENTICATION_REQUIRED:
    387     case REMOTE_SERVICE_DISABLED:
    388       // No point to run sync.
    389       return;
    390   }
    391 
    392   StartRemoteSync();
    393   StartLocalSync();
    394 }
    395 
    396 void SyncFileSystemService::StartRemoteSync() {
    397   // See if we cannot / should not start a new remote sync.
    398   if (remote_sync_running_ || pending_remote_changes_ == 0)
    399     return;
    400   // If we have registered a URL for waiting until sync is enabled on a
    401   // file (and the registerred URL seems to be still valid) it won't be
    402   // worth trying to start another remote sync.
    403   if (is_waiting_remote_sync_enabled_)
    404     return;
    405   DCHECK(sync_enabled_);
    406 
    407   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    408             "Calling ProcessRemoteChange for RemoteSync");
    409   remote_sync_running_ = true;
    410   remote_file_service_->ProcessRemoteChange(
    411       base::Bind(&SyncFileSystemService::DidProcessRemoteChange,
    412                  AsWeakPtr()));
    413 }
    414 
    415 void SyncFileSystemService::StartLocalSync() {
    416   // See if we cannot / should not start a new local sync.
    417   if (local_sync_running_ || pending_local_changes_ == 0)
    418     return;
    419   DCHECK(sync_enabled_);
    420 
    421   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    422             "Calling ProcessLocalChange for LocalSync");
    423   local_sync_running_ = true;
    424   local_file_service_->ProcessLocalChange(
    425       base::Bind(&SyncFileSystemService::DidProcessLocalChange,
    426                  AsWeakPtr()));
    427 }
    428 
    429 void SyncFileSystemService::DidProcessRemoteChange(
    430     SyncStatusCode status,
    431     const FileSystemURL& url) {
    432   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    433             "ProcessRemoteChange finished with status=%d (%s) for url=%s",
    434             status, SyncStatusCodeToString(status), url.DebugString().c_str());
    435   DCHECK(remote_sync_running_);
    436   remote_sync_running_ = false;
    437 
    438   if (status != SYNC_STATUS_NO_CHANGE_TO_SYNC &&
    439       remote_file_service_->GetCurrentState() != REMOTE_SERVICE_DISABLED) {
    440     DCHECK(url.is_valid());
    441     local_file_service_->ClearSyncFlagForURL(url);
    442   }
    443 
    444   if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) {
    445     // We seem to have no changes to work on for now.
    446     // TODO(kinuko): Might be better setting a timer to call MaybeStartSync.
    447     return;
    448   }
    449   if (status == SYNC_STATUS_FILE_BUSY) {
    450     is_waiting_remote_sync_enabled_ = true;
    451     local_file_service_->RegisterURLForWaitingSync(
    452         url, base::Bind(&SyncFileSystemService::OnSyncEnabledForRemoteSync,
    453                         AsWeakPtr()));
    454     return;
    455   }
    456 
    457   base::MessageLoopProxy::current()->PostTask(
    458       FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync,
    459                             AsWeakPtr()));
    460 }
    461 
    462 void SyncFileSystemService::DidProcessLocalChange(
    463     SyncStatusCode status, const FileSystemURL& url) {
    464   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    465             "ProcessLocalChange finished with status=%d (%s) for url=%s",
    466             status, SyncStatusCodeToString(status), url.DebugString().c_str());
    467   DCHECK(local_sync_running_);
    468   local_sync_running_ = false;
    469 
    470   if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC) {
    471     // We seem to have no changes to work on for now.
    472     return;
    473   }
    474 
    475   DCHECK(url.is_valid());
    476   local_file_service_->ClearSyncFlagForURL(url);
    477 
    478   base::MessageLoopProxy::current()->PostTask(
    479       FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync,
    480                             AsWeakPtr()));
    481 }
    482 
    483 void SyncFileSystemService::DidGetLocalChangeStatus(
    484     const SyncFileStatusCallback& callback,
    485     SyncStatusCode status,
    486     bool has_pending_local_changes) {
    487   callback.Run(
    488       status,
    489       has_pending_local_changes ?
    490           SYNC_FILE_STATUS_HAS_PENDING_CHANGES : SYNC_FILE_STATUS_SYNCED);
    491 }
    492 
    493 void SyncFileSystemService::OnSyncEnabledForRemoteSync() {
    494   is_waiting_remote_sync_enabled_ = false;
    495   MaybeStartSync();
    496 }
    497 
    498 void SyncFileSystemService::OnLocalChangeAvailable(int64 pending_changes) {
    499   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    500   DCHECK_GE(pending_changes, 0);
    501   if (pending_local_changes_ != pending_changes) {
    502     util::Log(logging::LOG_VERBOSE, FROM_HERE,
    503               "OnLocalChangeAvailable: %" PRId64, pending_changes);
    504   }
    505   pending_local_changes_ = pending_changes;
    506   if (pending_changes == 0)
    507     return;
    508 
    509   base::MessageLoopProxy::current()->PostTask(
    510       FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync,
    511                             AsWeakPtr()));
    512 }
    513 
    514 void SyncFileSystemService::OnRemoteChangeQueueUpdated(int64 pending_changes) {
    515   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    516   DCHECK_GE(pending_changes, 0);
    517 
    518   if (pending_remote_changes_ != pending_changes) {
    519     util::Log(logging::LOG_VERBOSE, FROM_HERE,
    520               "OnRemoteChangeAvailable: %" PRId64, pending_changes);
    521   }
    522   pending_remote_changes_ = pending_changes;
    523   if (pending_changes == 0)
    524     return;
    525 
    526   // The smallest change available might have changed from the previous one.
    527   // Reset the is_waiting_remote_sync_enabled_ flag so that we can retry.
    528   is_waiting_remote_sync_enabled_ = false;
    529 
    530   base::MessageLoopProxy::current()->PostTask(
    531       FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync,
    532                             AsWeakPtr()));
    533 }
    534 
    535 void SyncFileSystemService::OnRemoteServiceStateUpdated(
    536     RemoteServiceState state,
    537     const std::string& description) {
    538   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    539   util::Log(logging::LOG_INFO, FROM_HERE,
    540             "OnRemoteServiceStateChanged: %d %s", state, description.c_str());
    541 
    542   if (state == REMOTE_SERVICE_OK) {
    543     base::MessageLoopProxy::current()->PostTask(
    544         FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync,
    545                               AsWeakPtr()));
    546   }
    547 
    548   FOR_EACH_OBSERVER(
    549       SyncEventObserver, observers_,
    550       OnSyncStateUpdated(GURL(),
    551                          RemoteStateToSyncServiceState(state),
    552                          description));
    553 }
    554 
    555 void SyncFileSystemService::Observe(
    556     int type,
    557     const content::NotificationSource& source,
    558     const content::NotificationDetails& details) {
    559   // Event notification sequence.
    560   //
    561   // (User action)    (Notification type)
    562   // Install:         INSTALLED.
    563   // Update:          INSTALLED.
    564   // Uninstall:       UNINSTALLED.
    565   // Launch, Close:   No notification.
    566   // Enable:          ENABLED.
    567   // Disable:         UNLOADED(DISABLE).
    568   // Reload, Restart: UNLOADED(DISABLE) -> INSTALLED -> ENABLED.
    569   //
    570   switch (type) {
    571     case chrome::NOTIFICATION_EXTENSION_INSTALLED:
    572       HandleExtensionInstalled(details);
    573       break;
    574     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
    575       HandleExtensionUnloaded(type, details);
    576       break;
    577     case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
    578       HandleExtensionUninstalled(type, details);
    579       break;
    580     case chrome::NOTIFICATION_EXTENSION_ENABLED:
    581       HandleExtensionEnabled(type, details);
    582       break;
    583     default:
    584       NOTREACHED() << "Unknown notification.";
    585       break;
    586   }
    587 }
    588 
    589 void SyncFileSystemService::HandleExtensionInstalled(
    590     const content::NotificationDetails& details) {
    591   const extensions::Extension* extension =
    592       content::Details<const extensions::InstalledExtensionInfo>(details)->
    593           extension;
    594   GURL app_origin =
    595       extensions::Extension::GetBaseURLFromExtensionId(extension->id());
    596   DVLOG(1) << "Handle extension notification for INSTALLED: " << app_origin;
    597   // NOTE: When an app is uninstalled and re-installed in a sequence,
    598   // |local_file_service_| may still keeps |app_origin| as disabled origin.
    599   local_file_service_->SetOriginEnabled(app_origin, true);
    600 }
    601 
    602 void SyncFileSystemService::HandleExtensionUnloaded(
    603     int type,
    604     const content::NotificationDetails& details) {
    605   content::Details<const extensions::UnloadedExtensionInfo> info(details);
    606   std::string extension_id = info->extension->id();
    607   GURL app_origin =
    608       extensions::Extension::GetBaseURLFromExtensionId(extension_id);
    609   if (info->reason != extension_misc::UNLOAD_REASON_DISABLE)
    610     return;
    611   DVLOG(1) << "Handle extension notification for UNLOAD(DISABLE): "
    612            << app_origin;
    613   remote_file_service_->DisableOriginForTrackingChanges(
    614       app_origin,
    615       base::Bind(&DidHandleOriginForExtensionUnloadedEvent,
    616                  type, app_origin));
    617   local_file_service_->SetOriginEnabled(app_origin, false);
    618 }
    619 
    620 void SyncFileSystemService::HandleExtensionUninstalled(
    621     int type,
    622     const content::NotificationDetails& details) {
    623   std::string extension_id =
    624       content::Details<const extensions::Extension>(details)->id();
    625   GURL app_origin =
    626       extensions::Extension::GetBaseURLFromExtensionId(extension_id);
    627   DVLOG(1) << "Handle extension notification for UNINSTALLED: "
    628            << app_origin;
    629   remote_file_service_->UninstallOrigin(
    630       app_origin,
    631       base::Bind(&DidHandleOriginForExtensionUnloadedEvent,
    632                  type, app_origin));
    633   local_file_service_->SetOriginEnabled(app_origin, false);
    634 }
    635 
    636 void SyncFileSystemService::HandleExtensionEnabled(
    637     int type,
    638     const content::NotificationDetails& details) {
    639   std::string extension_id =
    640       content::Details<const extensions::Extension>(details)->id();
    641   GURL app_origin =
    642       extensions::Extension::GetBaseURLFromExtensionId(extension_id);
    643   DVLOG(1) << "Handle extension notification for ENABLED: " << app_origin;
    644   remote_file_service_->EnableOriginForTrackingChanges(
    645       app_origin,
    646       base::Bind(&DidHandleOriginForExtensionEnabledEvent, type, app_origin));
    647   local_file_service_->SetOriginEnabled(app_origin, true);
    648 }
    649 
    650 void SyncFileSystemService::OnStateChanged() {
    651   ProfileSyncServiceBase* profile_sync_service =
    652       ProfileSyncServiceFactory::GetForProfile(profile_);
    653   if (profile_sync_service)
    654     UpdateSyncEnabledStatus(profile_sync_service);
    655 }
    656 
    657 void SyncFileSystemService::OnFileStatusChanged(
    658     const FileSystemURL& url,
    659     SyncFileStatus sync_status,
    660     SyncAction action_taken,
    661     SyncDirection direction) {
    662   FOR_EACH_OBSERVER(
    663       SyncEventObserver, observers_,
    664       OnFileSynced(url, sync_status, action_taken, direction));
    665 }
    666 
    667 void SyncFileSystemService::UpdateSyncEnabledStatus(
    668     ProfileSyncServiceBase* profile_sync_service) {
    669   if (!profile_sync_service->HasSyncSetupCompleted())
    670     return;
    671   sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
    672       syncer::APPS);
    673   remote_file_service_->SetSyncEnabled(sync_enabled_);
    674   if (sync_enabled_) {
    675     base::MessageLoopProxy::current()->PostTask(
    676         FROM_HERE, base::Bind(&SyncFileSystemService::MaybeStartSync,
    677                               AsWeakPtr()));
    678   }
    679 }
    680 
    681 }  // namespace sync_file_system
    682