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.
5 #include "chrome/browser/extensions/app_data_migrator.h"
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"
21 using content::BrowserContext
;
22 using content::BrowserThread
;
23 using content::IndexedDBContext
;
24 using content::StoragePartition
;
25 using storage::FileSystemContext
;
26 using storage::SandboxFileSystemBackendDelegate
;
30 void MigrateOnFileSystemThread(FileSystemContext
* old_fs_context
,
31 FileSystemContext
* fs_context
,
32 const extensions::Extension
* extension
) {
34 old_fs_context
->default_file_task_runner()->RunsTasksOnCurrentThread());
36 SandboxFileSystemBackendDelegate
* old_sandbox_delegate
=
37 old_fs_context
->sandbox_delegate();
38 SandboxFileSystemBackendDelegate
* sandbox_delegate
=
39 fs_context
->sandbox_delegate();
42 extensions::Extension::GetBaseURLFromExtensionId(extension
->id());
44 scoped_ptr
<storage::SandboxFileSystemBackendDelegate::OriginEnumerator
>
45 enumerator(old_sandbox_delegate
->CreateOriginEnumerator());
47 // Find out if there is a file system that needs migration.
50 origin
= enumerator
->Next();
51 } while (origin
!= extension_url
&& !origin
.is_empty());
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
);
59 // Copy the persistent file system.
60 if (enumerator
->HasFileSystemType(storage::kFileSystemTypePersistent
)) {
61 old_sandbox_delegate
->CopyFileSystem(
62 extension_url
, storage::kFileSystemTypePersistent
, sandbox_delegate
);
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());
73 extensions::Extension::GetBaseURLFromExtensionId(extension
->id());
75 old_indexed_db_context
->CopyOriginData(extension_url
, indexed_db_context
);
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_CURRENTLY_ON(BrowserThread::UI
);
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()) {
91 FileSystemContext
* old_fs_context
= old_partition
->GetFileSystemContext();
92 FileSystemContext
* fs_context
= current_partition
->GetFileSystemContext();
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(
100 base::Bind(&MigrateOnFileSystemThread
, make_scoped_refptr(old_fs_context
),
101 make_scoped_refptr(fs_context
), make_scoped_refptr(extension
)),
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_CURRENTLY_ON(BrowserThread::UI
);
112 IndexedDBContext
* indexed_db_context
=
113 current_partition
->GetIndexedDBContext();
114 IndexedDBContext
* old_indexed_db_context
=
115 old_partition
->GetIndexedDBContext();
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
);
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
)),
135 namespace extensions
{
137 AppDataMigrator::AppDataMigrator(Profile
* profile
, ExtensionRegistry
* registry
)
138 : profile_(profile
), registry_(registry
), weak_factory_(this) {
141 AppDataMigrator::~AppDataMigrator() {
144 bool AppDataMigrator::NeedsMigration(const Extension
* old
,
145 const Extension
* extension
) {
146 return old
&& old
->is_legacy_packaged_app() && extension
->is_platform_app();
149 void AppDataMigrator::DoMigrationAndReply(const Extension
* old
,
150 const Extension
* extension
,
151 const base::Closure
& reply
) {
152 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
153 DCHECK(NeedsMigration(old
, extension
));
155 // This should retrieve the general storage partition.
156 content::StoragePartition
* old_partition
=
157 BrowserContext::GetStoragePartitionForSite(
158 profile_
, Extension::GetBaseURLFromExtensionId(extension
->id()));
160 // Enable the new extension so we can access its storage partition.
161 bool old_was_disabled
= registry_
->AddEnabled(extension
);
163 // This should create a new isolated partition for the new version of the
165 StoragePartition
* new_partition
= BrowserContext::GetStoragePartitionForSite(
166 profile_
, Extension::GetBaseURLFromExtensionId(extension
->id()));
168 // Now, restore the enabled/disabled state of the new and old extensions.
169 if (old_was_disabled
)
170 registry_
->RemoveEnabled(extension
->id());
172 registry_
->AddEnabled(old
);
174 MigrateLegacyPartition(weak_factory_
.GetWeakPtr(), old_partition
,
175 new_partition
, extension
, reply
);
178 } // namespace extensions