| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/file_system_provider/service.h" | 5 #include "chrome/browser/chromeos/file_system_provider/service.h" |
| 6 | 6 |
| 7 #include "base/files/file_path.h" | 7 #include "base/files/file_path.h" |
| 8 #include "base/prefs/pref_service.h" | 8 #include "base/prefs/pref_service.h" |
| 9 #include "base/prefs/scoped_user_pref_update.h" | 9 #include "base/prefs/scoped_user_pref_update.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 46 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 46 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| 47 } | 47 } |
| 48 | 48 |
| 49 Service::Service(Profile* profile, | 49 Service::Service(Profile* profile, |
| 50 extensions::ExtensionRegistry* extension_registry) | 50 extensions::ExtensionRegistry* extension_registry) |
| 51 : profile_(profile), | 51 : profile_(profile), |
| 52 extension_registry_(extension_registry), | 52 extension_registry_(extension_registry), |
| 53 file_system_factory_(base::Bind(CreateProvidedFileSystem)), | 53 file_system_factory_(base::Bind(CreateProvidedFileSystem)), |
| 54 weak_ptr_factory_(this) { | 54 weak_ptr_factory_(this) { |
| 55 extension_registry_->AddObserver(this); | 55 extension_registry_->AddObserver(this); |
| 56 |
| 57 // Store previously mounted file systems in order to be able to remount |
| 58 // them once related extensions are loaded. |
| 59 PrefService* pref_service = profile_->GetPrefs(); |
| 60 DCHECK(pref_service); |
| 61 |
| 62 const base::DictionaryValue* file_systems = |
| 63 pref_service->GetDictionary(prefs::kFileSystemProviderMounted); |
| 64 DCHECK(file_systems); |
| 65 |
| 66 file_systems_to_restore_.reset(file_systems->DeepCopy()); |
| 56 } | 67 } |
| 57 | 68 |
| 58 Service::~Service() { | 69 Service::~Service() { |
| 59 extension_registry_->RemoveObserver(this); | 70 extension_registry_->RemoveObserver(this); |
| 60 RememberFileSystems(); | |
| 61 | 71 |
| 72 // Provided file systems should be already unmounted because of receiving |
| 73 // OnExtensionUnload calls for each installed extension. However, for tests |
| 74 // we may still have mounted extensions. |
| 75 // TODO(mtomasz): Create a TestingService class and remove this code. |
| 62 ProvidedFileSystemMap::iterator it = file_system_map_.begin(); | 76 ProvidedFileSystemMap::iterator it = file_system_map_.begin(); |
| 63 while (it != file_system_map_.end()) { | 77 while (it != file_system_map_.end()) { |
| 64 const std::string file_system_id = | 78 const std::string file_system_id = |
| 65 it->second->GetFileSystemInfo().file_system_id(); | 79 it->second->GetFileSystemInfo().file_system_id(); |
| 66 const std::string extension_id = | 80 const std::string extension_id = |
| 67 it->second->GetFileSystemInfo().extension_id(); | 81 it->second->GetFileSystemInfo().extension_id(); |
| 68 ++it; | 82 ++it; |
| 69 const bool unmount_result = UnmountFileSystem(extension_id, file_system_id); | 83 const bool unmount_result = UnmountFileSystem( |
| 84 extension_id, file_system_id, UNMOUNT_REASON_SHUTDOWN); |
| 70 DCHECK(unmount_result); | 85 DCHECK(unmount_result); |
| 71 } | 86 } |
| 72 | 87 |
| 73 DCHECK_EQ(0u, file_system_map_.size()); | 88 DCHECK_EQ(0u, file_system_map_.size()); |
| 74 STLDeleteValues(&file_system_map_); | 89 STLDeleteValues(&file_system_map_); |
| 75 } | 90 } |
| 76 | 91 |
| 77 // static | 92 // static |
| 78 Service* Service::Get(content::BrowserContext* context) { | 93 Service* Service::Get(content::BrowserContext* context) { |
| 79 return ServiceFactory::Get(context); | 94 return ServiceFactory::Get(context); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 // mount_path = /provided/b33f1337-41-5aa5 | 165 // mount_path = /provided/b33f1337-41-5aa5 |
| 151 ProvidedFileSystemInfo file_system_info( | 166 ProvidedFileSystemInfo file_system_info( |
| 152 extension_id, file_system_id, file_system_name, mount_path); | 167 extension_id, file_system_id, file_system_name, mount_path); |
| 153 | 168 |
| 154 ProvidedFileSystemInterface* file_system = | 169 ProvidedFileSystemInterface* file_system = |
| 155 file_system_factory_.Run(profile_, file_system_info); | 170 file_system_factory_.Run(profile_, file_system_info); |
| 156 DCHECK(file_system); | 171 DCHECK(file_system); |
| 157 file_system_map_[FileSystemKey(extension_id, file_system_id)] = file_system; | 172 file_system_map_[FileSystemKey(extension_id, file_system_id)] = file_system; |
| 158 mount_point_name_to_key_map_[mount_point_name] = | 173 mount_point_name_to_key_map_[mount_point_name] = |
| 159 FileSystemKey(extension_id, file_system_id); | 174 FileSystemKey(extension_id, file_system_id); |
| 175 RememberFileSystem(file_system_info); |
| 160 | 176 |
| 161 FOR_EACH_OBSERVER( | 177 FOR_EACH_OBSERVER( |
| 162 Observer, | 178 Observer, |
| 163 observers_, | 179 observers_, |
| 164 OnProvidedFileSystemMount(file_system_info, base::File::FILE_OK)); | 180 OnProvidedFileSystemMount(file_system_info, base::File::FILE_OK)); |
| 165 | 181 |
| 166 return true; | 182 return true; |
| 167 } | 183 } |
| 168 | 184 |
| 169 bool Service::UnmountFileSystem(const std::string& extension_id, | 185 bool Service::UnmountFileSystem(const std::string& extension_id, |
| 170 const std::string& file_system_id) { | 186 const std::string& file_system_id, |
| 187 UnmountReason reason) { |
| 171 DCHECK(thread_checker_.CalledOnValidThread()); | 188 DCHECK(thread_checker_.CalledOnValidThread()); |
| 172 | 189 |
| 173 const ProvidedFileSystemMap::iterator file_system_it = | 190 const ProvidedFileSystemMap::iterator file_system_it = |
| 174 file_system_map_.find(FileSystemKey(extension_id, file_system_id)); | 191 file_system_map_.find(FileSystemKey(extension_id, file_system_id)); |
| 175 if (file_system_it == file_system_map_.end()) { | 192 if (file_system_it == file_system_map_.end()) { |
| 176 const ProvidedFileSystemInfo empty_file_system_info; | 193 const ProvidedFileSystemInfo empty_file_system_info; |
| 177 FOR_EACH_OBSERVER( | 194 FOR_EACH_OBSERVER( |
| 178 Observer, | 195 Observer, |
| 179 observers_, | 196 observers_, |
| 180 OnProvidedFileSystemUnmount(empty_file_system_info, | 197 OnProvidedFileSystemUnmount(empty_file_system_info, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 200 return false; | 217 return false; |
| 201 } | 218 } |
| 202 | 219 |
| 203 FOR_EACH_OBSERVER( | 220 FOR_EACH_OBSERVER( |
| 204 Observer, | 221 Observer, |
| 205 observers_, | 222 observers_, |
| 206 OnProvidedFileSystemUnmount(file_system_info, base::File::FILE_OK)); | 223 OnProvidedFileSystemUnmount(file_system_info, base::File::FILE_OK)); |
| 207 | 224 |
| 208 mount_point_name_to_key_map_.erase(mount_point_name); | 225 mount_point_name_to_key_map_.erase(mount_point_name); |
| 209 | 226 |
| 227 if (reason == UNMOUNT_REASON_USER) { |
| 228 ForgetFileSystem(file_system_info.extension_id(), |
| 229 file_system_info.file_system_id()); |
| 230 } |
| 231 |
| 210 delete file_system_it->second; | 232 delete file_system_it->second; |
| 211 file_system_map_.erase(file_system_it); | 233 file_system_map_.erase(file_system_it); |
| 212 | 234 |
| 213 return true; | 235 return true; |
| 214 } | 236 } |
| 215 | 237 |
| 216 bool Service::RequestUnmount(const std::string& extension_id, | 238 bool Service::RequestUnmount(const std::string& extension_id, |
| 217 const std::string& file_system_id) { | 239 const std::string& file_system_id) { |
| 218 DCHECK(thread_checker_.CalledOnValidThread()); | 240 DCHECK(thread_checker_.CalledOnValidThread()); |
| 219 | 241 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 if (file_system_it == file_system_map_.end()) | 273 if (file_system_it == file_system_map_.end()) |
| 252 return NULL; | 274 return NULL; |
| 253 | 275 |
| 254 return file_system_it->second; | 276 return file_system_it->second; |
| 255 } | 277 } |
| 256 | 278 |
| 257 void Service::OnExtensionUnloaded( | 279 void Service::OnExtensionUnloaded( |
| 258 content::BrowserContext* browser_context, | 280 content::BrowserContext* browser_context, |
| 259 const extensions::Extension* extension, | 281 const extensions::Extension* extension, |
| 260 extensions::UnloadedExtensionInfo::Reason reason) { | 282 extensions::UnloadedExtensionInfo::Reason reason) { |
| 261 // If the reason is not a profile shutdown, then forget the mounted file | |
| 262 // systems from preferences. | |
| 263 if (reason != extensions::UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN) | |
| 264 ForgetFileSystems(extension->id()); | |
| 265 | |
| 266 // Unmount all of the provided file systems associated with this extension. | 283 // Unmount all of the provided file systems associated with this extension. |
| 267 ProvidedFileSystemMap::iterator it = file_system_map_.begin(); | 284 ProvidedFileSystemMap::iterator it = file_system_map_.begin(); |
| 268 while (it != file_system_map_.end()) { | 285 while (it != file_system_map_.end()) { |
| 269 const ProvidedFileSystemInfo& file_system_info = | 286 const ProvidedFileSystemInfo& file_system_info = |
| 270 it->second->GetFileSystemInfo(); | 287 it->second->GetFileSystemInfo(); |
| 271 // Advance the iterator beforehand, otherwise it will become invalidated | 288 // Advance the iterator beforehand, otherwise it will become invalidated |
| 272 // by the UnmountFileSystem() call. | 289 // by the UnmountFileSystem() call. |
| 273 ++it; | 290 ++it; |
| 274 if (file_system_info.extension_id() == extension->id()) { | 291 if (file_system_info.extension_id() == extension->id()) { |
| 275 const bool unmount_result = UnmountFileSystem( | 292 const bool unmount_result = UnmountFileSystem( |
| 276 file_system_info.extension_id(), file_system_info.file_system_id()); | 293 file_system_info.extension_id(), |
| 294 file_system_info.file_system_id(), |
| 295 reason == extensions::UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN |
| 296 ? UNMOUNT_REASON_SHUTDOWN |
| 297 : UNMOUNT_REASON_USER); |
| 277 DCHECK(unmount_result); | 298 DCHECK(unmount_result); |
| 278 } | 299 } |
| 279 } | 300 } |
| 280 } | 301 } |
| 281 | 302 |
| 282 void Service::OnExtensionLoaded(content::BrowserContext* browser_context, | 303 void Service::OnExtensionLoaded(content::BrowserContext* browser_context, |
| 283 const extensions::Extension* extension) { | 304 const extensions::Extension* extension) { |
| 284 RestoreFileSystems(extension->id()); | 305 RestoreFileSystems(extension->id()); |
| 285 } | 306 } |
| 286 | 307 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 307 // Notify observers about failure in unmounting, since mount() will not be | 328 // Notify observers about failure in unmounting, since mount() will not be |
| 308 // called by the provided file system. In case of success mount() will be | 329 // called by the provided file system. In case of success mount() will be |
| 309 // invoked, and observers notified, so there is no need to call them now. | 330 // invoked, and observers notified, so there is no need to call them now. |
| 310 if (error != base::File::FILE_OK) { | 331 if (error != base::File::FILE_OK) { |
| 311 FOR_EACH_OBSERVER(Observer, | 332 FOR_EACH_OBSERVER(Observer, |
| 312 observers_, | 333 observers_, |
| 313 OnProvidedFileSystemUnmount(file_system_info, error)); | 334 OnProvidedFileSystemUnmount(file_system_info, error)); |
| 314 } | 335 } |
| 315 } | 336 } |
| 316 | 337 |
| 317 void Service::RememberFileSystems() { | 338 void Service::RememberFileSystem( |
| 318 base::DictionaryValue extensions; | 339 const ProvidedFileSystemInfo& file_system_info) { |
| 319 const std::vector<ProvidedFileSystemInfo> file_system_info_list = | 340 base::DictionaryValue* file_system = new base::DictionaryValue(); |
| 320 GetProvidedFileSystemInfoList(); | 341 file_system->SetString(kPrefKeyFileSystemId, |
| 321 | 342 file_system_info.file_system_id()); |
| 322 for (std::vector<ProvidedFileSystemInfo>::const_iterator it = | 343 file_system->SetString(kPrefKeyFileSystemName, |
| 323 file_system_info_list.begin(); | 344 file_system_info.file_system_name()); |
| 324 it != file_system_info_list.end(); | |
| 325 ++it) { | |
| 326 base::ListValue* file_systems = NULL; | |
| 327 if (!extensions.GetList(it->extension_id(), &file_systems)) { | |
| 328 file_systems = new base::ListValue(); | |
| 329 extensions.Set(it->extension_id(), file_systems); | |
| 330 } | |
| 331 | |
| 332 base::DictionaryValue* file_system = new base::DictionaryValue(); | |
| 333 file_system->SetString(kPrefKeyFileSystemId, it->file_system_id()); | |
| 334 file_system->SetString(kPrefKeyFileSystemName, it->file_system_name()); | |
| 335 file_systems->Append(file_system); | |
| 336 } | |
| 337 | 345 |
| 338 PrefService* pref_service = profile_->GetPrefs(); | 346 PrefService* pref_service = profile_->GetPrefs(); |
| 339 DCHECK(pref_service); | 347 DCHECK(pref_service); |
| 340 pref_service->Set(prefs::kFileSystemProviderMounted, extensions); | 348 |
| 341 pref_service->CommitPendingWrite(); | 349 DictionaryPrefUpdate dict_update(pref_service, |
| 350 prefs::kFileSystemProviderMounted); |
| 351 |
| 352 base::DictionaryValue* file_systems_per_extension = NULL; |
| 353 if (!dict_update->GetDictionary(file_system_info.extension_id(), |
| 354 &file_systems_per_extension)) { |
| 355 file_systems_per_extension = new base::DictionaryValue(); |
| 356 dict_update->Set(file_system_info.extension_id(), |
| 357 file_systems_per_extension); |
| 358 } |
| 359 |
| 360 file_systems_per_extension->SetWithoutPathExpansion( |
| 361 file_system_info.file_system_id(), file_system); |
| 342 } | 362 } |
| 343 | 363 |
| 344 void Service::ForgetFileSystems(const std::string& extension_id) { | 364 void Service::ForgetFileSystem(const std::string& extension_id, |
| 365 const std::string& file_system_id) { |
| 345 PrefService* pref_service = profile_->GetPrefs(); | 366 PrefService* pref_service = profile_->GetPrefs(); |
| 346 DCHECK(pref_service); | 367 DCHECK(pref_service); |
| 347 | 368 |
| 348 DictionaryPrefUpdate update(pref_service, prefs::kFileSystemProviderMounted); | 369 DictionaryPrefUpdate dict_update(pref_service, |
| 349 base::DictionaryValue* extensions = update.Get(); | 370 prefs::kFileSystemProviderMounted); |
| 350 DCHECK(extensions); | |
| 351 | 371 |
| 352 extensions->Remove(extension_id, NULL); | 372 base::DictionaryValue* file_systems_per_extension = NULL; |
| 373 if (!dict_update->GetDictionary(extension_id, &file_systems_per_extension)) { |
| 374 return; // Nothing to forget. |
| 375 } |
| 376 |
| 377 file_systems_per_extension->RemoveWithoutPathExpansion(file_system_id, NULL); |
| 378 if (!file_systems_per_extension->size()) |
| 379 dict_update->Remove(extension_id, NULL); |
| 353 } | 380 } |
| 354 | 381 |
| 355 void Service::RestoreFileSystems(const std::string& extension_id) { | 382 void Service::RestoreFileSystems(const std::string& extension_id) { |
| 356 PrefService* pref_service = profile_->GetPrefs(); | 383 const base::DictionaryValue* file_systems_per_extension = NULL; |
| 357 DCHECK(pref_service); | 384 if (!file_systems_to_restore_->GetDictionary(extension_id, |
| 385 &file_systems_per_extension)) { |
| 386 return; // Nothing to restore. |
| 387 } |
| 358 | 388 |
| 359 const base::DictionaryValue* extensions = | 389 for (base::DictionaryValue::Iterator it(*file_systems_per_extension); |
| 360 pref_service->GetDictionary(prefs::kFileSystemProviderMounted); | 390 !it.IsAtEnd(); |
| 361 DCHECK(extensions); | 391 it.Advance()) { |
| 362 | 392 const base::Value* file_system_value = NULL; |
| 363 const base::ListValue* file_systems = NULL; | |
| 364 | |
| 365 if (!extensions->GetList(extension_id, &file_systems)) | |
| 366 return; | |
| 367 | |
| 368 for (size_t i = 0; i < file_systems->GetSize(); ++i) { | |
| 369 const base::DictionaryValue* file_system = NULL; | 393 const base::DictionaryValue* file_system = NULL; |
| 370 file_systems->GetDictionary(i, &file_system); | 394 file_systems_per_extension->GetWithoutPathExpansion(it.key(), |
| 371 DCHECK(file_system); | 395 &file_system_value); |
| 396 DCHECK(file_system_value); |
| 372 | 397 |
| 373 std::string file_system_id; | 398 std::string file_system_id; |
| 374 file_system->GetString(kPrefKeyFileSystemId, &file_system_id); | |
| 375 DCHECK(!file_system_id.empty()); | |
| 376 | |
| 377 std::string file_system_name; | 399 std::string file_system_name; |
| 378 file_system->GetString(kPrefKeyFileSystemName, &file_system_name); | 400 if (file_system_value->GetAsDictionary(&file_system)) { |
| 379 DCHECK(!file_system_name.empty()); | 401 file_system->GetString(kPrefKeyFileSystemId, &file_system_id); |
| 402 file_system->GetString(kPrefKeyFileSystemName, &file_system_name); |
| 403 } |
| 380 | 404 |
| 381 if (file_system_id.empty() || file_system_name.empty()) { | 405 if (file_system_id.empty() || file_system_name.empty()) { |
| 382 LOG(ERROR) | 406 LOG(ERROR) |
| 383 << "Malformed provided file system information in preferences."; | 407 << "Malformed provided file system information in preferences."; |
| 384 continue; | 408 continue; |
| 385 } | 409 } |
| 386 | 410 |
| 387 const bool result = | 411 const bool result = |
| 388 MountFileSystem(extension_id, file_system_id, file_system_name); | 412 MountFileSystem(extension_id, file_system_id, file_system_name); |
| 389 if (!result) { | 413 if (!result) { |
| 390 LOG(ERROR) << "Failed to restore a provided file system from " | 414 LOG(ERROR) << "Failed to restore a provided file system from " |
| 391 << "preferences: " << extension_id << ", " << file_system_id | 415 << "preferences: " << extension_id << ", " << file_system_id |
| 392 << ", " << file_system_name << "."; | 416 << ", " << file_system_name << "."; |
| 417 // In case of remounting during startup, forget the file system from |
| 418 // preferences. |
| 419 ForgetFileSystem(extension_id, file_system_id); |
| 393 } | 420 } |
| 394 } | 421 } |
| 422 |
| 423 file_systems_to_restore_->Remove(extension_id, NULL); |
| 395 } | 424 } |
| 396 | 425 |
| 397 } // namespace file_system_provider | 426 } // namespace file_system_provider |
| 398 } // namespace chromeos | 427 } // namespace chromeos |
| OLD | NEW |