blob: 79d8502df2bd88e5508b84611bb26f9cc4d8665e [file] [log] [blame]
ryanackley48bedbd2015-01-27 23:12:141// 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
20using base::WeakPtr;
21using content::BrowserContext;
22using content::BrowserThread;
23using content::IndexedDBContext;
24using content::StoragePartition;
25using storage::FileSystemContext;
26using storage::SandboxFileSystemBackendDelegate;
27
28namespace {
29
30void MigrateOnFileSystemThread(FileSystemContext* old_fs_context,
31 FileSystemContext* fs_context,
32 const extensions::Extension* extension) {
33 DCHECK(
peary2be588082017-05-17 01:59:4934 old_fs_context->default_file_task_runner()->RunsTasksInCurrentSequence());
ryanackley48bedbd2015-01-27 23:12:1435
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
dchengc963c7142016-04-08 03:55:2244 std::unique_ptr<storage::SandboxFileSystemBackendDelegate::OriginEnumerator>
ryanackley48bedbd2015-01-27 23:12:1445 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
67void MigrateOnIndexedDBThread(IndexedDBContext* old_indexed_db_context,
68 IndexedDBContext* indexed_db_context,
69 const extensions::Extension* extension) {
peary2be588082017-05-17 01:59:4970 DCHECK(old_indexed_db_context->TaskRunner()->RunsTasksInCurrentSequence());
ryanackley48bedbd2015-01-27 23:12:1471
72 GURL extension_url =
73 extensions::Extension::GetBaseURLFromExtensionId(extension->id());
74
75 old_indexed_db_context->CopyOriginData(extension_url, indexed_db_context);
76}
77
78void MigrateFileSystem(WeakPtr<extensions::AppDataMigrator> migrator,
79 StoragePartition* old_partition,
80 StoragePartition* current_partition,
81 const extensions::Extension* extension,
82 const base::Closure& reply) {
anujk.sharmaf2a0b4e2015-04-24 17:53:2983 DCHECK_CURRENTLY_ON(BrowserThread::UI);
ryanackley48bedbd2015-01-27 23:12:1484
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,
tzik8d880ee2017-04-20 19:46:24100 base::BindOnce(
101 &MigrateOnFileSystemThread, base::RetainedRef(old_fs_context),
102 base::RetainedRef(fs_context), base::RetainedRef(extension)),
ryanackley48bedbd2015-01-27 23:12:14103 reply);
104}
105
106void MigrateLegacyPartition(WeakPtr<extensions::AppDataMigrator> migrator,
107 StoragePartition* old_partition,
108 StoragePartition* current_partition,
109 const extensions::Extension* extension,
110 const base::Closure& reply) {
anujk.sharmaf2a0b4e2015-04-24 17:53:29111 DCHECK_CURRENTLY_ON(BrowserThread::UI);
ryanackley48bedbd2015-01-27 23:12:14112
113 IndexedDBContext* indexed_db_context =
114 current_partition->GetIndexedDBContext();
115 IndexedDBContext* old_indexed_db_context =
116 old_partition->GetIndexedDBContext();
117
118 // Create a closure for the file system migration. This is the next step in
119 // the migration flow after the IndexedDB migration.
120 base::Closure migrate_fs =
121 base::Bind(&MigrateFileSystem, migrator, old_partition, current_partition,
vmpstra34d11322016-03-21 20:28:47122 base::RetainedRef(extension), reply);
ryanackley48bedbd2015-01-27 23:12:14123
124 // Perform the IndexedDB migration on the old context's sequenced task
125 // runner. After completion, it should call MigrateFileSystem.
126 old_indexed_db_context->TaskRunner()->PostTaskAndReply(
vmpstra34d11322016-03-21 20:28:47127 FROM_HERE,
tzik8d880ee2017-04-20 19:46:24128 base::BindOnce(
vmpstra34d11322016-03-21 20:28:47129 &MigrateOnIndexedDBThread, base::RetainedRef(old_indexed_db_context),
130 base::RetainedRef(indexed_db_context), base::RetainedRef(extension)),
ryanackley48bedbd2015-01-27 23:12:14131 migrate_fs);
132}
133
134} // namespace
135
136namespace extensions {
137
138AppDataMigrator::AppDataMigrator(Profile* profile, ExtensionRegistry* registry)
139 : profile_(profile), registry_(registry), weak_factory_(this) {
140}
141
142AppDataMigrator::~AppDataMigrator() {
143}
144
145bool AppDataMigrator::NeedsMigration(const Extension* old,
146 const Extension* extension) {
147 return old && old->is_legacy_packaged_app() && extension->is_platform_app();
148}
149
150void AppDataMigrator::DoMigrationAndReply(const Extension* old,
151 const Extension* extension,
152 const base::Closure& reply) {
anujk.sharmaf2a0b4e2015-04-24 17:53:29153 DCHECK_CURRENTLY_ON(BrowserThread::UI);
ryanackley48bedbd2015-01-27 23:12:14154 DCHECK(NeedsMigration(old, extension));
155
156 // This should retrieve the general storage partition.
157 content::StoragePartition* old_partition =
158 BrowserContext::GetStoragePartitionForSite(
159 profile_, Extension::GetBaseURLFromExtensionId(extension->id()));
160
161 // Enable the new extension so we can access its storage partition.
162 bool old_was_disabled = registry_->AddEnabled(extension);
163
164 // This should create a new isolated partition for the new version of the
165 // extension.
166 StoragePartition* new_partition = BrowserContext::GetStoragePartitionForSite(
167 profile_, Extension::GetBaseURLFromExtensionId(extension->id()));
168
169 // Now, restore the enabled/disabled state of the new and old extensions.
170 if (old_was_disabled)
171 registry_->RemoveEnabled(extension->id());
172 else
173 registry_->AddEnabled(old);
174
175 MigrateLegacyPartition(weak_factory_.GetWeakPtr(), old_partition,
176 new_partition, extension, reply);
177}
178
179} // namespace extensions