sync_file_system_backend.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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 23using content::BrowserThread; 24 25namespace sync_file_system { 26 27namespace { 28 29bool 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 38SyncFileSystemBackend::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 46void 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 57Profile* SyncFileSystemBackend::ProfileHolder::GetProfile() { 58 DCHECK(CalledOnUIThread()); 59 return profile_; 60} 61 62SyncFileSystemBackend::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 74SyncFileSystemBackend::~SyncFileSystemBackend() { 75 RevokeSyncableFileSystem(); 76 77 if (change_tracker_) { 78 GetDelegate()->file_task_runner()->DeleteSoon( 79 FROM_HERE, change_tracker_.release()); 80 } 81 82 if (profile_holder_ && !CalledOnUIThread()) { 83 BrowserThread::DeleteSoon( 84 BrowserThread::UI, FROM_HERE, profile_holder_.release()); 85 } 86} 87 88// static 89SyncFileSystemBackend* SyncFileSystemBackend::CreateForTesting() { 90 DCHECK(CalledOnUIThread()); 91 SyncFileSystemBackend* backend = new SyncFileSystemBackend(NULL); 92 backend->skip_initialize_syncfs_service_for_testing_ = true; 93 return backend; 94} 95 96bool SyncFileSystemBackend::CanHandleType( 97 fileapi::FileSystemType type) const { 98 return type == fileapi::kFileSystemTypeSyncable || 99 type == fileapi::kFileSystemTypeSyncableForInternalSync; 100} 101 102void SyncFileSystemBackend::Initialize(fileapi::FileSystemContext* context) { 103 DCHECK(context); 104 DCHECK(!context_); 105 context_ = context; 106 107 fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate(); 108 delegate->RegisterQuotaUpdateObserver(fileapi::kFileSystemTypeSyncable); 109 delegate->RegisterQuotaUpdateObserver( 110 fileapi::kFileSystemTypeSyncableForInternalSync); 111} 112 113void SyncFileSystemBackend::OpenFileSystem( 114 const GURL& origin_url, 115 fileapi::FileSystemType type, 116 fileapi::OpenFileSystemMode mode, 117 const OpenFileSystemCallback& callback) { 118 DCHECK(CanHandleType(type)); 119 120 if (skip_initialize_syncfs_service_for_testing_) { 121 GetDelegate()->OpenFileSystem(origin_url, type, mode, callback, 122 GetSyncableFileSystemRootURI(origin_url)); 123 return; 124 } 125 126 // It is safe to pass Unretained(this) since |context_| owns it. 127 SyncStatusCallback initialize_callback = 128 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService, 129 base::Unretained(this), make_scoped_refptr(context_), 130 origin_url, type, mode, callback); 131 InitializeSyncFileSystemService(origin_url, initialize_callback); 132} 133 134fileapi::AsyncFileUtil* SyncFileSystemBackend::GetAsyncFileUtil( 135 fileapi::FileSystemType type) { 136 return GetDelegate()->file_util(); 137} 138 139fileapi::CopyOrMoveFileValidatorFactory* 140SyncFileSystemBackend::GetCopyOrMoveFileValidatorFactory( 141 fileapi::FileSystemType type, 142 base::PlatformFileError* error_code) { 143 DCHECK(error_code); 144 *error_code = base::PLATFORM_FILE_OK; 145 return NULL; 146} 147 148fileapi::FileSystemOperation* 149SyncFileSystemBackend::CreateFileSystemOperation( 150 const fileapi::FileSystemURL& url, 151 fileapi::FileSystemContext* context, 152 base::PlatformFileError* error_code) const { 153 DCHECK(CanHandleType(url.type())); 154 DCHECK(context); 155 DCHECK(error_code); 156 157 scoped_ptr<fileapi::FileSystemOperationContext> operation_context = 158 GetDelegate()->CreateFileSystemOperationContext(url, context, error_code); 159 if (!operation_context) 160 return NULL; 161 162 if (url.type() == fileapi::kFileSystemTypeSyncableForInternalSync) { 163 return fileapi::FileSystemOperation::Create( 164 url, context, operation_context.Pass()); 165 } 166 167 return new SyncableFileSystemOperation( 168 url, context, operation_context.Pass()); 169} 170 171scoped_ptr<webkit_blob::FileStreamReader> 172SyncFileSystemBackend::CreateFileStreamReader( 173 const fileapi::FileSystemURL& url, 174 int64 offset, 175 const base::Time& expected_modification_time, 176 fileapi::FileSystemContext* context) const { 177 DCHECK(CanHandleType(url.type())); 178 return GetDelegate()->CreateFileStreamReader( 179 url, offset, expected_modification_time, context); 180} 181 182scoped_ptr<fileapi::FileStreamWriter> 183SyncFileSystemBackend::CreateFileStreamWriter( 184 const fileapi::FileSystemURL& url, 185 int64 offset, 186 fileapi::FileSystemContext* context) const { 187 DCHECK(CanHandleType(url.type())); 188 return GetDelegate()->CreateFileStreamWriter( 189 url, offset, context, fileapi::kFileSystemTypeSyncableForInternalSync); 190} 191 192fileapi::FileSystemQuotaUtil* SyncFileSystemBackend::GetQuotaUtil() { 193 return GetDelegate(); 194} 195 196// static 197SyncFileSystemBackend* SyncFileSystemBackend::GetBackend( 198 const fileapi::FileSystemContext* file_system_context) { 199 DCHECK(file_system_context); 200 return static_cast<SyncFileSystemBackend*>( 201 file_system_context->GetFileSystemBackend( 202 fileapi::kFileSystemTypeSyncable)); 203} 204 205void SyncFileSystemBackend::SetLocalFileChangeTracker( 206 scoped_ptr<LocalFileChangeTracker> tracker) { 207 DCHECK(!change_tracker_); 208 DCHECK(tracker); 209 change_tracker_ = tracker.Pass(); 210 211 fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate(); 212 delegate->AddFileUpdateObserver( 213 fileapi::kFileSystemTypeSyncable, 214 change_tracker_.get(), 215 delegate->file_task_runner()); 216 delegate->AddFileChangeObserver( 217 fileapi::kFileSystemTypeSyncable, 218 change_tracker_.get(), 219 delegate->file_task_runner()); 220} 221 222void SyncFileSystemBackend::set_sync_context( 223 LocalFileSyncContext* sync_context) { 224 DCHECK(!sync_context_); 225 sync_context_ = sync_context; 226} 227 228fileapi::SandboxFileSystemBackendDelegate* 229SyncFileSystemBackend::GetDelegate() const { 230 DCHECK(context_); 231 DCHECK(context_->sandbox_delegate()); 232 return context_->sandbox_delegate(); 233} 234 235void SyncFileSystemBackend::InitializeSyncFileSystemService( 236 const GURL& origin_url, 237 const SyncStatusCallback& callback) { 238 // Repost to switch from IO thread to UI thread. 239 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 241 // It is safe to pass Unretained(this) (see comments in OpenFileSystem()). 242 BrowserThread::PostTask( 243 BrowserThread::UI, FROM_HERE, 244 base::Bind(&SyncFileSystemBackend::InitializeSyncFileSystemService, 245 base::Unretained(this), origin_url, callback)); 246 return; 247 } 248 249 if (!profile_holder_->GetProfile()) { 250 // Profile was destroyed. 251 callback.Run(SYNC_FILE_ERROR_FAILED); 252 return; 253 } 254 255 SyncFileSystemService* service = SyncFileSystemServiceFactory::GetForProfile( 256 profile_holder_->GetProfile()); 257 DCHECK(service); 258 service->InitializeForApp(context_, origin_url, callback); 259} 260 261void SyncFileSystemBackend::DidInitializeSyncFileSystemService( 262 fileapi::FileSystemContext* context, 263 const GURL& origin_url, 264 fileapi::FileSystemType type, 265 fileapi::OpenFileSystemMode mode, 266 const OpenFileSystemCallback& callback, 267 SyncStatusCode status) { 268 // Repost to switch from UI thread to IO thread. 269 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 271 // It is safe to pass Unretained(this) since |context| owns it. 272 BrowserThread::PostTask( 273 BrowserThread::IO, FROM_HERE, 274 base::Bind(&SyncFileSystemBackend::DidInitializeSyncFileSystemService, 275 base::Unretained(this), make_scoped_refptr(context), 276 origin_url, type, mode, callback, status)); 277 return; 278 } 279 280 if (status != sync_file_system::SYNC_STATUS_OK) { 281 callback.Run(GURL(), std::string(), 282 SyncStatusCodeToPlatformFileError(status)); 283 return; 284 } 285 286 GetDelegate()->OpenFileSystem(origin_url, type, mode, callback, 287 GetSyncableFileSystemRootURI(origin_url)); 288} 289 290} // namespace sync_file_system 291