Chromium Code Reviews| Index: chrome/browser/extensions/app_data_migrator.cc |
| diff --git a/chrome/browser/extensions/app_data_migrator.cc b/chrome/browser/extensions/app_data_migrator.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..01aada00dfa241928195ba51880d5262cb1f4e55 |
| --- /dev/null |
| +++ b/chrome/browser/extensions/app_data_migrator.cc |
| @@ -0,0 +1,195 @@ |
| +// Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/extensions/app_data_migrator.h" |
| + |
| +#include "base/files/file_util.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "content/public/browser/browser_context.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/indexed_db_context.h" |
| +#include "content/public/browser/storage_partition.h" |
| +#include "extensions/browser/extension_registry.h" |
| +#include "extensions/common/extension.h" |
| +#include "storage/browser/fileapi/file_system_context.h" |
| +#include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h" |
| +#include "storage/common/fileapi/file_system_types.h" |
| + |
| +using content::BrowserContext; |
| +using content::BrowserThread; |
| +using content::IndexedDBContext; |
| +using content::StoragePartition; |
| +using storage::FileSystemContext; |
| +using storage::SandboxFileSystemBackendDelegate; |
| + |
| +namespace { |
| + |
| +void CopyFileSystem(SandboxFileSystemBackendDelegate* old_sandbox_delegate, |
| + SandboxFileSystemBackendDelegate* sandbox_delegate, |
| + const GURL& origin, |
| + storage::FileSystemType type) { |
| + CHECK(old_sandbox_delegate->file_task_runner()->RunsTasksOnCurrentThread()); |
| + |
| + base::FilePath old_base_path = |
| + old_sandbox_delegate->GetBaseDirectoryForOriginAndType( |
| + origin, type, false); |
|
tzik
2014/11/20 06:56:21
The backing database may be left open here.
Could
|
| + |
| + if (base::PathExists(old_base_path)) { |
| + // There shouldn't be an existing file system directory in the new |
| + // partition. |
| + DCHECK(!base::PathExists(sandbox_delegate->GetBaseDirectoryForOriginAndType( |
| + origin, type, false))); |
| + |
| + base::FilePath base_path = |
| + sandbox_delegate->GetBaseDirectoryForOriginAndType(origin, type, true); |
| + |
| + base::CopyDirectory(old_base_path, base_path.DirName(), true); |
| + } |
| +} |
| + |
| +void MigrateOnFileSystemThread( |
| + SandboxFileSystemBackendDelegate* old_sandbox_delegate, |
| + SandboxFileSystemBackendDelegate* sandbox_delegate, |
| + const extensions::Extension* extension) { |
| + CHECK(old_sandbox_delegate->file_task_runner()->RunsTasksOnCurrentThread()); |
| + |
| + GURL extension_url = |
| + extensions::Extension::GetBaseURLFromExtensionId(extension->id()); |
| + |
| + scoped_ptr<storage::SandboxFileSystemBackendDelegate::OriginEnumerator> |
| + enumerator(old_sandbox_delegate->CreateOriginEnumerator()); |
| + |
| + // Find out if there is a file system that needs migration. |
| + GURL origin; |
| + do { |
| + origin = enumerator->Next(); |
| + } while (origin != extension_url && !origin.is_empty()); |
| + |
| + if (!origin.is_empty()) { |
| + // Copy the temporary file system. |
| + if (enumerator->HasFileSystemType(storage::kFileSystemTypeTemporary)) { |
| + CopyFileSystem(old_sandbox_delegate, |
| + sandbox_delegate, |
| + extension_url, |
| + storage::kFileSystemTypeTemporary); |
| + } |
| + // Copy the persistent file system. |
| + if (enumerator->HasFileSystemType(storage::kFileSystemTypePersistent)) { |
| + CopyFileSystem(old_sandbox_delegate, |
| + sandbox_delegate, |
| + extension_url, |
| + storage::kFileSystemTypePersistent); |
| + } |
| + } |
| +} |
| + |
| +void MigrateOnIndexedDBThread(IndexedDBContext* old_indexed_db_context, |
| + IndexedDBContext* indexed_db_context, |
| + const extensions::Extension* extension) { |
| + CHECK(old_indexed_db_context->TaskRunner()->RunsTasksOnCurrentThread()); |
| + |
| + GURL extension_url = |
| + extensions::Extension::GetBaseURLFromExtensionId(extension->id()); |
| + |
| + old_indexed_db_context->CopyOriginData(extension_url, indexed_db_context); |
| +} |
| +void MigrateFileSystem(StoragePartition* old_partition, |
| + StoragePartition* current_partition, |
| + const extensions::Extension* extension, |
| + const base::Closure& reply) { |
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + // Retrieve the fs contexts and sandbox delegates in preparation for |
| + // migration. |
| + FileSystemContext* old_fs_context = old_partition->GetFileSystemContext(); |
| + FileSystemContext* fs_context = current_partition->GetFileSystemContext(); |
| + |
| + SandboxFileSystemBackendDelegate* old_sandbox_delegate = |
| + old_fs_context->sandbox_delegate(); |
| + SandboxFileSystemBackendDelegate* sandbox_delegate = |
| + fs_context->sandbox_delegate(); |
| + |
| + // Perform the file system migration on the old file system's |
| + // sequenced task runner. This is to ensure it queues after any |
| + // in-flight file system operations. After it completes, it should |
| + // invoke the original callback passed into DoMigrationAndReply. |
| + old_sandbox_delegate->file_task_runner()->PostTaskAndReply( |
| + FROM_HERE, |
| + base::Bind(&MigrateOnFileSystemThread, |
| + old_sandbox_delegate, |
| + sandbox_delegate, |
| + make_scoped_refptr(extension)), |
| + reply); |
| +} |
| +void MigrateLegacyPartition(StoragePartition* old_partition, |
| + StoragePartition* current_partition, |
| + const extensions::Extension* extension, |
| + const base::Closure& reply) { |
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + // Retrieve both IndexedDB contexts in preparation for migration. |
| + IndexedDBContext* indexed_db_context = |
| + current_partition->GetIndexedDBContext(); |
| + IndexedDBContext* old_indexed_db_context = |
| + old_partition->GetIndexedDBContext(); |
| + |
| + // Create a closure for the file system migration. This is the next step in |
| + // the migration flow after the IndexedDB migration. |
| + base::Closure migrateFs = base::Bind( |
| + &MigrateFileSystem, old_partition, current_partition, extension, reply); |
| + |
| + // Perform the IndexedDB migration on the old context's sequenced task |
| + // runner. After completion, it should call MigrateFileSystem. |
| + old_indexed_db_context->TaskRunner()->PostTaskAndReply( |
| + FROM_HERE, |
| + base::Bind(&MigrateOnIndexedDBThread, |
| + old_indexed_db_context, |
| + indexed_db_context, |
| + make_scoped_refptr(extension)), |
| + migrateFs); |
| +} |
| + |
| +} // namespace |
| + |
| +namespace extensions { |
| + |
| +AppDataMigrator::AppDataMigrator(Profile* profile, ExtensionRegistry* registry) |
| + : profile_(profile), registry_(registry) { |
| +} |
| + |
| +bool AppDataMigrator::NeedsMigration(const Extension* old, |
| + const Extension* extension) { |
| + return old && old->is_legacy_packaged_app() && extension->is_platform_app(); |
| +} |
| + |
| +void AppDataMigrator::DoMigrationAndReply(const Extension* old, |
| + const Extension* extension, |
| + const base::Closure& reply) { |
| + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + // This should retrieve the general storage partition. |
| + content::StoragePartition* old_partition = |
| + BrowserContext::GetStoragePartitionForSite( |
| + profile_, Extension::GetBaseURLFromExtensionId(extension->id())); |
| + |
| + // Enable the new extension so we can access its storage partition. |
| + bool oldWasDisabled = registry_->AddEnabled(extension); |
| + |
| + // This should create a new isolated partition for the new version of the |
| + // extension. |
| + StoragePartition* new_partition = BrowserContext::GetStoragePartitionForSite( |
| + profile_, Extension::GetBaseURLFromExtensionId(extension->id())); |
| + |
| + // Now, restore the enabled/disabled state of the new and old extensions. |
| + if (!oldWasDisabled) { |
| + registry_->AddEnabled(old); |
| + } else { |
| + registry_->RemoveEnabled(extension->id()); |
| + } |
| + |
| + // Begin the actual migration flow. |
| + MigrateLegacyPartition(old_partition, new_partition, extension, reply); |
| +} |
| + |
| +} // namespace extensions |