| // Copyright 2015 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 "base/memory/weak_ptr.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 base::WeakPtr; | 
 | 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) { | 
 |   DCHECK( | 
 |       old_fs_context->default_file_task_runner()->RunsTasksInCurrentSequence()); | 
 |  | 
 |   SandboxFileSystemBackendDelegate* old_sandbox_delegate = | 
 |       old_fs_context->sandbox_delegate(); | 
 |   SandboxFileSystemBackendDelegate* sandbox_delegate = | 
 |       fs_context->sandbox_delegate(); | 
 |  | 
 |   GURL extension_url = | 
 |       extensions::Extension::GetBaseURLFromExtensionId(extension->id()); | 
 |  | 
 |   std::unique_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) { | 
 |   DCHECK(old_indexed_db_context->TaskRunner()->RunsTasksInCurrentSequence()); | 
 |  | 
 |   GURL extension_url = | 
 |       extensions::Extension::GetBaseURLFromExtensionId(extension->id()); | 
 |  | 
 |   old_indexed_db_context->CopyOriginData(extension_url, indexed_db_context); | 
 | } | 
 |  | 
 | void MigrateFileSystem(WeakPtr<extensions::AppDataMigrator> migrator, | 
 |                        StoragePartition* old_partition, | 
 |                        StoragePartition* current_partition, | 
 |                        const extensions::Extension* extension, | 
 |                        const base::Closure& reply) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   // Since this method is static and it's being run as a closure task, check to | 
 |   // make sure the calling object is still around. | 
 |   if (!migrator.get()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   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::BindOnce( | 
 |           &MigrateOnFileSystemThread, base::RetainedRef(old_fs_context), | 
 |           base::RetainedRef(fs_context), base::RetainedRef(extension)), | 
 |       reply); | 
 | } | 
 |  | 
 | void MigrateLegacyPartition(WeakPtr<extensions::AppDataMigrator> migrator, | 
 |                             StoragePartition* old_partition, | 
 |                             StoragePartition* current_partition, | 
 |                             const extensions::Extension* extension, | 
 |                             const base::Closure& reply) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   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, migrator, old_partition, current_partition, | 
 |                  base::RetainedRef(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::BindOnce( | 
 |           &MigrateOnIndexedDBThread, base::RetainedRef(old_indexed_db_context), | 
 |           base::RetainedRef(indexed_db_context), base::RetainedRef(extension)), | 
 |       migrate_fs); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | namespace extensions { | 
 |  | 
 | AppDataMigrator::AppDataMigrator(Profile* profile, ExtensionRegistry* registry) | 
 |     : profile_(profile), registry_(registry), weak_factory_(this) { | 
 | } | 
 |  | 
 | AppDataMigrator::~AppDataMigrator() { | 
 | } | 
 |  | 
 | 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) { | 
 |   DCHECK_CURRENTLY_ON(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_->RemoveEnabled(extension->id()); | 
 |   else | 
 |     registry_->AddEnabled(old); | 
 |  | 
 |   MigrateLegacyPartition(weak_factory_.GetWeakPtr(), old_partition, | 
 |                          new_partition, extension, reply); | 
 | } | 
 |  | 
 | }  // namespace extensions |