Home | History | Annotate | Download | only in local
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
      6 
      7 #include "base/logging.h"
      8 #include "chrome/browser/chrome_notification_types.h"
      9 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
     10 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
     11 #include "chrome/browser/sync_file_system/local/syncable_file_system_operation.h"
     12 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
     13 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
     14 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     15 #include "content/public/browser/browser_thread.h"
     16 #include "content/public/browser/notification_service.h"
     17 #include "webkit/browser/blob/file_stream_reader.h"
     18 #include "webkit/browser/fileapi/file_stream_writer.h"
     19 #include "webkit/browser/fileapi/file_system_context.h"
     20 #include "webkit/browser/fileapi/file_system_operation.h"
     21 #include "webkit/common/fileapi/file_system_util.h"
     22 
     23 using content::BrowserThread;
     24 
     25 namespace sync_file_system {
     26 
     27 namespace {
     28 
     29 bool CalledOnUIThread() {
     30   // Ensure that these methods are called on the UI thread, except for unittests
     31   // where a UI thread might not have been created.
     32   return BrowserThread::CurrentlyOn(BrowserThread::UI) ||
     33          !BrowserThread::IsMessageLoopValid(BrowserThread::UI);
     34 }
     35 
     36 }  // namespace
     37 
     38 SyncFileSystemBackend::ProfileHolder::ProfileHolder(Profile* profile)
     39     : profile_(profile) {
     40   DCHECK(CalledOnUIThread());
     41   registrar_.Add(this,
     42                  chrome::NOTIFICATION_PROFILE_DESTROYED,
     43                  content::Source<Profile>(profile_));
     44 }
     45 
     46 void SyncFileSystemBackend::ProfileHolder::Observe(
     47     int type,
     48     const content::NotificationSource& source,
     49     const content::NotificationDetails& details) {
     50   DCHECK(CalledOnUIThread());
     51   DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
     52   DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
     53   profile_ = NULL;
     54   registrar_.RemoveAll();
     55 }
     56 
     57 Profile* SyncFileSystemBackend::ProfileHolder::GetProfile() {
     58   DCHECK(CalledOnUIThread());
     59   return profile_;
     60 }
     61 
     62 SyncFileSystemBackend::SyncFileSystemBackend(Profile* profile)
     63     : context_(NULL),
     64       skip_initialize_syncfs_service_for_testing_(false) {
     65   DCHECK(CalledOnUIThread());
     66   if (profile)
     67     profile_holder_.reset(new ProfileHolder(profile));
     68 
     69   // Register the service name here to enable to crack an URL on SyncFileSystem
     70   // even if SyncFileSystemService has not started yet.
     71   RegisterSyncableFileSystem();
     72 }
     73 
     74 SyncFileSystemBackend::~SyncFileSystemBackend() {
     75   if (change_tracker_) {
     76     GetDelegate()->file_task_runner()->DeleteSoon(
     77         FROM_HERE, change_tracker_.release());
     78   }
     79 
     80   if (profile_holder_ && !CalledOnUIThread()) {
     81     BrowserThread::DeleteSoon(
     82         BrowserThread::UI, FROM_HERE, profile_holder_.release());
     83   }
     84 }
     85 
     86 // static
     87 SyncFileSystemBackend* SyncFileSystemBackend::CreateForTesting() {
     88   DCHECK(CalledOnUIThread());
     89   SyncFileSystemBackend* backend = new SyncFileSystemBackend(NULL);
     90   backend->skip_initialize_syncfs_service_for_testing_ = true;
     91   return backend;
     92 }
     93 
     94 bool SyncFileSystemBackend::CanHandleType(
     95     fileapi::FileSystemType type) const {
     96   return type == fileapi::kFileSystemTypeSyncable ||
     97          type == fileapi::kFileSystemTypeSyncableForInternalSync;
     98 }
     99 
    100 void SyncFileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
    101   DCHECK(context);
    102   DCHECK(!context_);
    103   context_ = context;
    104 
    105   fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate();
    106   delegate->RegisterQuotaUpdateObserver(fileapi::kFileSystemTypeSyncable);
    107   delegate->RegisterQuotaUpdateObserver(
    108       fileapi::kFileSystemTypeSyncableForInternalSync);
    109 }
    110 
    111 void SyncFileSystemBackend::OpenFileSystem(
    112     const GURL& origin_url,
    113     fileapi::FileSystemType type,
    114     fileapi::OpenFileSystemMode mode,
    115     const OpenFileSystemCallback& callback) {
    116   DCHECK(CanHandleType(type));
    117 
    118   if (skip_initialize_syncfs_service_for_testing_) {
    119     GetDelegate()->OpenFileSystem(origin_url, type, mode, callback,
    120                                   GetSyncableFileSystemRootURI(origin_url));
    121     return;
    122   }
    123 
    124   // It is safe to pass Unretained(this) since |context_| owns it.
    125   SyncStatusCallback initialize_callback =
    126       base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService,
    127                  base::Unretained(this), make_scoped_refptr(context_),
    128                  origin_url, type, mode, callback);
    129   InitializeSyncFileSystemService(origin_url, initialize_callback);
    130 }
    131 
    132 fileapi::AsyncFileUtil* SyncFileSystemBackend::GetAsyncFileUtil(
    133     fileapi::FileSystemType type) {
    134   return GetDelegate()->file_util();
    135 }
    136 
    137 fileapi::CopyOrMoveFileValidatorFactory*
    138 SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
    139     fileapi::FileSystemType type,
    140     base::PlatformFileError* error_code) {
    141   DCHECK(error_code);
    142   *error_code = base::PLATFORM_FILE_OK;
    143   return NULL;
    144 }
    145 
    146 fileapi::FileSystemOperation*
    147 SyncFileSystemBackend::CreateFileSystemOperation(
    148     const fileapi::FileSystemURL& url,
    149     fileapi::FileSystemContext* context,
    150     base::PlatformFileError* error_code) const {
    151   DCHECK(CanHandleType(url.type()));
    152   DCHECK(context);
    153   DCHECK(error_code);
    154 
    155   scoped_ptr<fileapi::FileSystemOperationContext> operation_context =
    156       GetDelegate()->CreateFileSystemOperationContext(url, context, error_code);
    157   if (!operation_context)
    158     return NULL;
    159 
    160   if (url.type() == fileapi::kFileSystemTypeSyncableForInternalSync) {
    161     return fileapi::FileSystemOperation::Create(
    162         url, context, operation_context.Pass());
    163   }
    164 
    165   return new SyncableFileSystemOperation(
    166       url, context, operation_context.Pass());
    167 }
    168 
    169 scoped_ptr<webkit_blob::FileStreamReader>
    170 SyncFileSystemBackend::CreateFileStreamReader(
    171     const fileapi::FileSystemURL& url,
    172     int64 offset,
    173     const base::Time& expected_modification_time,
    174     fileapi::FileSystemContext* context) const {
    175   DCHECK(CanHandleType(url.type()));
    176   return GetDelegate()->CreateFileStreamReader(
    177       url, offset, expected_modification_time, context);
    178 }
    179 
    180 scoped_ptr<fileapi::FileStreamWriter>
    181 SyncFileSystemBackend::CreateFileStreamWriter(
    182     const fileapi::FileSystemURL& url,
    183     int64 offset,
    184     fileapi::FileSystemContext* context) const {
    185   DCHECK(CanHandleType(url.type()));
    186   return GetDelegate()->CreateFileStreamWriter(
    187       url, offset, context, fileapi::kFileSystemTypeSyncableForInternalSync);
    188 }
    189 
    190 fileapi::FileSystemQuotaUtil* SyncFileSystemBackend::GetQuotaUtil() {
    191   return GetDelegate();
    192 }
    193 
    194 // static
    195 SyncFileSystemBackend* SyncFileSystemBackend::GetBackend(
    196     const fileapi::FileSystemContext* file_system_context) {
    197   DCHECK(file_system_context);
    198   return static_cast<SyncFileSystemBackend*>(
    199       file_system_context->GetFileSystemBackend(
    200           fileapi::kFileSystemTypeSyncable));
    201 }
    202 
    203 void SyncFileSystemBackend::SetLocalFileChangeTracker(
    204     scoped_ptr<LocalFileChangeTracker> tracker) {
    205   DCHECK(!change_tracker_);
    206   DCHECK(tracker);
    207   change_tracker_ = tracker.Pass();
    208 
    209   fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate();
    210   delegate->AddFileUpdateObserver(
    211       fileapi::kFileSystemTypeSyncable,
    212       change_tracker_.get(),
    213       delegate->file_task_runner());
    214   delegate->AddFileChangeObserver(
    215       fileapi::kFileSystemTypeSyncable,
    216       change_tracker_.get(),
    217       delegate->file_task_runner());
    218 }
    219 
    220 void SyncFileSystemBackend::set_sync_context(
    221     LocalFileSyncContext* sync_context) {
    222   DCHECK(!sync_context_);
    223   sync_context_ = sync_context;
    224 }
    225 
    226 fileapi::SandboxFileSystemBackendDelegate*
    227 SyncFileSystemBackend::GetDelegate() const {
    228   DCHECK(context_);
    229   DCHECK(context_->sandbox_delegate());
    230   return context_->sandbox_delegate();
    231 }
    232 
    233 void SyncFileSystemBackend::InitializeSyncFileSystemService(
    234     const GURL& origin_url,
    235     const SyncStatusCallback& callback) {
    236   // Repost to switch from IO thread to UI thread.
    237   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    238     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    239     // It is safe to pass Unretained(this) (see comments in OpenFileSystem()).
    240     BrowserThread::PostTask(
    241         BrowserThread::UI, FROM_HERE,
    242         base::Bind(&SyncFileSystemBackend::InitializeSyncFileSystemService,
    243                    base::Unretained(this), origin_url, callback));
    244     return;
    245   }
    246 
    247   if (!profile_holder_->GetProfile()) {
    248     // Profile was destroyed.
    249     callback.Run(SYNC_FILE_ERROR_FAILED);
    250     return;
    251   }
    252 
    253   SyncFileSystemService* service = SyncFileSystemServiceFactory::GetForProfile(
    254           profile_holder_->GetProfile());
    255   DCHECK(service);
    256   service->InitializeForApp(context_, origin_url, callback);
    257 }
    258 
    259 void SyncFileSystemBackend::DidInitializeSyncFileSystemService(
    260     fileapi::FileSystemContext* context,
    261     const GURL& origin_url,
    262     fileapi::FileSystemType type,
    263     fileapi::OpenFileSystemMode mode,
    264     const OpenFileSystemCallback& callback,
    265     SyncStatusCode status) {
    266   // Repost to switch from UI thread to IO thread.
    267   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
    268     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    269     // It is safe to pass Unretained(this) since |context| owns it.
    270     BrowserThread::PostTask(
    271         BrowserThread::IO, FROM_HERE,
    272         base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService,
    273                    base::Unretained(this), make_scoped_refptr(context),
    274                    origin_url, type, mode, callback, status));
    275     return;
    276   }
    277 
    278   if (status != sync_file_system::SYNC_STATUS_OK) {
    279     callback.Run(GURL(), std::string(),
    280                  SyncStatusCodeToPlatformFileError(status));
    281     return;
    282   }
    283 
    284   callback.Run(GetSyncableFileSystemRootURI(origin_url),
    285                GetFileSystemName(origin_url, type),
    286                base::PLATFORM_FILE_OK);
    287 }
    288 
    289 }  // namespace sync_file_system
    290