OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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/extensions/app_data_migrator.h" |
| 6 |
| 7 #include "base/files/file_util.h" |
| 8 #include "base/memory/weak_ptr.h" |
| 9 #include "chrome/browser/profiles/profile.h" |
| 10 #include "content/public/browser/browser_context.h" |
| 11 #include "content/public/browser/browser_thread.h" |
| 12 #include "content/public/browser/indexed_db_context.h" |
| 13 #include "content/public/browser/storage_partition.h" |
| 14 #include "extensions/browser/extension_registry.h" |
| 15 #include "extensions/common/extension.h" |
| 16 #include "storage/browser/fileapi/file_system_context.h" |
| 17 #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h" |
| 18 #include "storage/common/fileapi/file_system_types.h" |
| 19 |
| 20 using base::WeakPtr; |
| 21 using content::BrowserContext; |
| 22 using content::BrowserThread; |
| 23 using content::IndexedDBContext; |
| 24 using content::StoragePartition; |
| 25 using storage::FileSystemContext; |
| 26 using storage::SandboxFileSystemBackendDelegate; |
| 27 |
| 28 namespace { |
| 29 |
| 30 void MigrateOnFileSystemThread(FileSystemContext* old_fs_context, |
| 31 FileSystemContext* fs_context, |
| 32 const extensions::Extension* extension) { |
| 33 DCHECK( |
| 34 old_fs_context->default_file_task_runner()->RunsTasksOnCurrentThread()); |
| 35 |
| 36 SandboxFileSystemBackendDelegate* old_sandbox_delegate = |
| 37 old_fs_context->sandbox_delegate(); |
| 38 SandboxFileSystemBackendDelegate* sandbox_delegate = |
| 39 fs_context->sandbox_delegate(); |
| 40 |
| 41 GURL extension_url = |
| 42 extensions::Extension::GetBaseURLFromExtensionId(extension->id()); |
| 43 |
| 44 scoped_ptr<storage::SandboxFileSystemBackendDelegate::OriginEnumerator> |
| 45 enumerator(old_sandbox_delegate->CreateOriginEnumerator()); |
| 46 |
| 47 // Find out if there is a file system that needs migration. |
| 48 GURL origin; |
| 49 do { |
| 50 origin = enumerator->Next(); |
| 51 } while (origin != extension_url && !origin.is_empty()); |
| 52 |
| 53 if (!origin.is_empty()) { |
| 54 // Copy the temporary file system. |
| 55 if (enumerator->HasFileSystemType(storage::kFileSystemTypeTemporary)) { |
| 56 old_sandbox_delegate->CopyFileSystem( |
| 57 extension_url, storage::kFileSystemTypeTemporary, sandbox_delegate); |
| 58 } |
| 59 // Copy the persistent file system. |
| 60 if (enumerator->HasFileSystemType(storage::kFileSystemTypePersistent)) { |
| 61 old_sandbox_delegate->CopyFileSystem( |
| 62 extension_url, storage::kFileSystemTypePersistent, sandbox_delegate); |
| 63 } |
| 64 } |
| 65 } |
| 66 |
| 67 void MigrateOnIndexedDBThread(IndexedDBContext* old_indexed_db_context, |
| 68 IndexedDBContext* indexed_db_context, |
| 69 const extensions::Extension* extension) { |
| 70 DCHECK(old_indexed_db_context->TaskRunner()->RunsTasksOnCurrentThread()); |
| 71 |
| 72 GURL extension_url = |
| 73 extensions::Extension::GetBaseURLFromExtensionId(extension->id()); |
| 74 |
| 75 old_indexed_db_context->CopyOriginData(extension_url, indexed_db_context); |
| 76 } |
| 77 |
| 78 void MigrateFileSystem(WeakPtr<extensions::AppDataMigrator> migrator, |
| 79 StoragePartition* old_partition, |
| 80 StoragePartition* current_partition, |
| 81 const extensions::Extension* extension, |
| 82 const base::Closure& reply) { |
| 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 84 |
| 85 // Since this method is static and it's being run as a closure task, check to |
| 86 // make sure the calling object is still around. |
| 87 if (!migrator.get()) { |
| 88 return; |
| 89 } |
| 90 |
| 91 FileSystemContext* old_fs_context = old_partition->GetFileSystemContext(); |
| 92 FileSystemContext* fs_context = current_partition->GetFileSystemContext(); |
| 93 |
| 94 // Perform the file system migration on the old file system's |
| 95 // sequenced task runner. This is to ensure it queues after any |
| 96 // in-flight file system operations. After it completes, it should |
| 97 // invoke the original callback passed into DoMigrationAndReply. |
| 98 old_fs_context->default_file_task_runner()->PostTaskAndReply( |
| 99 FROM_HERE, |
| 100 base::Bind(&MigrateOnFileSystemThread, make_scoped_refptr(old_fs_context), |
| 101 make_scoped_refptr(fs_context), make_scoped_refptr(extension)), |
| 102 reply); |
| 103 } |
| 104 |
| 105 void MigrateLegacyPartition(WeakPtr<extensions::AppDataMigrator> migrator, |
| 106 StoragePartition* old_partition, |
| 107 StoragePartition* current_partition, |
| 108 const extensions::Extension* extension, |
| 109 const base::Closure& reply) { |
| 110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 111 |
| 112 IndexedDBContext* indexed_db_context = |
| 113 current_partition->GetIndexedDBContext(); |
| 114 IndexedDBContext* old_indexed_db_context = |
| 115 old_partition->GetIndexedDBContext(); |
| 116 |
| 117 // Create a closure for the file system migration. This is the next step in |
| 118 // the migration flow after the IndexedDB migration. |
| 119 base::Closure migrate_fs = |
| 120 base::Bind(&MigrateFileSystem, migrator, old_partition, current_partition, |
| 121 make_scoped_refptr(extension), reply); |
| 122 |
| 123 // Perform the IndexedDB migration on the old context's sequenced task |
| 124 // runner. After completion, it should call MigrateFileSystem. |
| 125 old_indexed_db_context->TaskRunner()->PostTaskAndReply( |
| 126 FROM_HERE, base::Bind(&MigrateOnIndexedDBThread, |
| 127 make_scoped_refptr(old_indexed_db_context), |
| 128 make_scoped_refptr(indexed_db_context), |
| 129 make_scoped_refptr(extension)), |
| 130 migrate_fs); |
| 131 } |
| 132 |
| 133 } // namespace |
| 134 |
| 135 namespace extensions { |
| 136 |
| 137 AppDataMigrator::AppDataMigrator(Profile* profile, ExtensionRegistry* registry) |
| 138 : profile_(profile), registry_(registry), weak_factory_(this) { |
| 139 } |
| 140 |
| 141 AppDataMigrator::~AppDataMigrator() { |
| 142 } |
| 143 |
| 144 bool AppDataMigrator::NeedsMigration(const Extension* old, |
| 145 const Extension* extension) { |
| 146 return old && old->is_legacy_packaged_app() && extension->is_platform_app(); |
| 147 } |
| 148 |
| 149 void AppDataMigrator::DoMigrationAndReply(const Extension* old, |
| 150 const Extension* extension, |
| 151 const base::Closure& reply) { |
| 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 153 DCHECK(NeedsMigration(old, extension)); |
| 154 |
| 155 // This should retrieve the general storage partition. |
| 156 content::StoragePartition* old_partition = |
| 157 BrowserContext::GetStoragePartitionForSite( |
| 158 profile_, Extension::GetBaseURLFromExtensionId(extension->id())); |
| 159 |
| 160 // Enable the new extension so we can access its storage partition. |
| 161 bool old_was_disabled = registry_->AddEnabled(extension); |
| 162 |
| 163 // This should create a new isolated partition for the new version of the |
| 164 // extension. |
| 165 StoragePartition* new_partition = BrowserContext::GetStoragePartitionForSite( |
| 166 profile_, Extension::GetBaseURLFromExtensionId(extension->id())); |
| 167 |
| 168 // Now, restore the enabled/disabled state of the new and old extensions. |
| 169 if (old_was_disabled) |
| 170 registry_->RemoveEnabled(extension->id()); |
| 171 else |
| 172 registry_->AddEnabled(old); |
| 173 |
| 174 MigrateLegacyPartition(weak_factory_.GetWeakPtr(), old_partition, |
| 175 new_partition, extension, reply); |
| 176 } |
| 177 |
| 178 } // namespace extensions |
OLD | NEW |