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..e0cf8d8aafdd1b5065fcace7135345d08b346b28 |
--- /dev/null |
+++ b/chrome/browser/extensions/app_data_migrator.cc |
@@ -0,0 +1,167 @@ |
+// Copyright (c) 2014 The Chromium Authors. All rights reserved. |
cmumford
2014/12/12 18:43:23
nit: no "(c)"
|
+// 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 MigrateOnFileSystemThread(FileSystemContext* old_fs_context, |
+ FileSystemContext* fs_context, |
+ const extensions::Extension* extension) { |
+ CHECK(old_fs_context->default_file_task_runner()->RunsTasksOnCurrentThread()); |
+ |
+ SandboxFileSystemBackendDelegate* old_sandbox_delegate = |
+ old_fs_context->sandbox_delegate(); |
+ SandboxFileSystemBackendDelegate* sandbox_delegate = |
+ fs_context->sandbox_delegate(); |
+ |
+ 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)) { |
+ old_sandbox_delegate->CopyFileSystem( |
+ extension_url, storage::kFileSystemTypeTemporary, sandbox_delegate); |
+ } |
+ // Copy the persistent file system. |
+ if (enumerator->HasFileSystemType(storage::kFileSystemTypePersistent)) { |
+ old_sandbox_delegate->CopyFileSystem( |
+ extension_url, storage::kFileSystemTypePersistent, sandbox_delegate); |
+ } |
+ } |
+} |
+ |
+void MigrateOnIndexedDBThread(IndexedDBContext* old_indexed_db_context, |
+ IndexedDBContext* indexed_db_context, |
+ const extensions::Extension* extension) { |
+ CHECK(old_indexed_db_context->TaskRunner()->RunsTasksOnCurrentThread()); |
cmumford
2014/12/12 18:43:23
Question: In Chrome there are 640 DCHECK's for Run
|
+ |
+ 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 in preparation for migration. |
+ FileSystemContext* old_fs_context = old_partition->GetFileSystemContext(); |
+ FileSystemContext* fs_context = current_partition->GetFileSystemContext(); |
+ |
+ // 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_fs_context->default_file_task_runner()->PostTaskAndReply( |
+ FROM_HERE, |
+ base::Bind(&MigrateOnFileSystemThread, make_scoped_refptr(old_fs_context), |
+ make_scoped_refptr(fs_context), 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 migrate_fs = |
+ base::Bind(&MigrateFileSystem, old_partition, current_partition, |
+ make_scoped_refptr(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, |
+ make_scoped_refptr(old_indexed_db_context), |
+ make_scoped_refptr(indexed_db_context), |
+ make_scoped_refptr(extension)), |
+ migrate_fs); |
+} |
+ |
+} // 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)); |
+ DCHECK(NeedsMigration(old, extension)); |
+ |
+ // 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 old_was_disabled = 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 (!old_was_disabled) { |
+ registry_->AddEnabled(old); |
+ } else { |
+ registry_->RemoveEnabled(extension->id()); |
+ } |
+ |
+ // Begin the actual migration flow. |
+ MigrateLegacyPartition(old_partition, new_partition, extension, reply); |
+} |
+ |
+} // namespace extensions |