sync_file_system_backend.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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/fileapi/file_system_context.h" 18#include "webkit/browser/fileapi/file_system_file_stream_reader.h" 19#include "webkit/browser/fileapi/file_system_operation.h" 20#include "webkit/browser/fileapi/sandbox_file_stream_writer.h" 21#include "webkit/browser/fileapi/sandbox_quota_observer.h" 22#include "webkit/common/fileapi/file_system_util.h" 23 24using content::BrowserThread; 25 26namespace sync_file_system { 27 28namespace { 29 30bool CalledOnUIThread() { 31 // Ensure that these methods are called on the UI thread, except for unittests 32 // where a UI thread might not have been created. 33 return BrowserThread::CurrentlyOn(BrowserThread::UI) || 34 !BrowserThread::IsMessageLoopValid(BrowserThread::UI); 35} 36 37} // namespace 38 39SyncFileSystemBackend::ProfileHolder::ProfileHolder(Profile* profile) 40 : profile_(profile) { 41 DCHECK(CalledOnUIThread()); 42 registrar_.Add(this, 43 chrome::NOTIFICATION_PROFILE_DESTROYED, 44 content::Source<Profile>(profile_)); 45} 46 47void SyncFileSystemBackend::ProfileHolder::Observe( 48 int type, 49 const content::NotificationSource& source, 50 const content::NotificationDetails& details) { 51 DCHECK(CalledOnUIThread()); 52 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); 53 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); 54 profile_ = NULL; 55 registrar_.RemoveAll(); 56} 57 58Profile* SyncFileSystemBackend::ProfileHolder::GetProfile() { 59 DCHECK(CalledOnUIThread()); 60 return profile_; 61} 62 63SyncFileSystemBackend::SyncFileSystemBackend(Profile* profile) 64 : context_(NULL), 65 skip_initialize_syncfs_service_for_testing_(false) { 66 DCHECK(CalledOnUIThread()); 67 if (profile) 68 profile_holder_.reset(new ProfileHolder(profile)); 69} 70 71SyncFileSystemBackend::~SyncFileSystemBackend() { 72 if (change_tracker_) { 73 GetDelegate()->file_task_runner()->DeleteSoon( 74 FROM_HERE, change_tracker_.release()); 75 } 76 77 if (profile_holder_ && !CalledOnUIThread()) { 78 BrowserThread::DeleteSoon( 79 BrowserThread::UI, FROM_HERE, profile_holder_.release()); 80 } 81} 82 83// static 84SyncFileSystemBackend* SyncFileSystemBackend::CreateForTesting() { 85 DCHECK(CalledOnUIThread()); 86 SyncFileSystemBackend* backend = new SyncFileSystemBackend(NULL); 87 backend->skip_initialize_syncfs_service_for_testing_ = true; 88 return backend; 89} 90 91bool SyncFileSystemBackend::CanHandleType( 92 fileapi::FileSystemType type) const { 93 return type == fileapi::kFileSystemTypeSyncable || 94 type == fileapi::kFileSystemTypeSyncableForInternalSync; 95} 96 97void SyncFileSystemBackend::Initialize(fileapi::FileSystemContext* context) { 98 DCHECK(context); 99 DCHECK(!context_); 100 context_ = context; 101 102 fileapi::SandboxFileSystemBackendDelegate* delegate = GetDelegate(); 103 delegate->AddFileUpdateObserver( 104 fileapi::kFileSystemTypeSyncable, 105 delegate->quota_observer(), 106 delegate->file_task_runner()); 107 delegate->AddFileUpdateObserver( 108 fileapi::kFileSystemTypeSyncableForInternalSync, 109 delegate->quota_observer(), 110 delegate->file_task_runner()); 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