1 // Copyright (c) 2012 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/webdata/web_data_service_factory.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/profiles/incognito_helpers.h"
11 #include "chrome/browser/sync/glue/sync_start_util.h"
12 #include "chrome/browser/ui/profile_error_dialog.h"
13 #include "chrome/browser/webdata/autocomplete_syncable_service.h"
14 #include "chrome/browser/webdata/autofill_profile_syncable_service.h"
15 #include "chrome/browser/webdata/keyword_table.h"
16 #include "chrome/browser/webdata/logins_table.h"
17 #include "chrome/browser/webdata/token_service_table.h"
18 #include "chrome/browser/webdata/token_web_data.h"
19 #include "chrome/browser/webdata/web_apps_table.h"
20 #include "chrome/browser/webdata/web_data_service.h"
21 #include "chrome/browser/webdata/web_intents_table.h"
22 #include "components/autofill/core/browser/autofill_country.h"
23 #include "components/autofill/core/browser/webdata/autofill_table.h"
24 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
25 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
26 #include "components/webdata/common/webdata_constants.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "grit/chromium_strings.h"
29 #include "grit/generated_resources.h"
30
31 using autofill::AutofillWebDataService;
32 using content::BrowserThread;
33
34 namespace {
35
36 // Callback to show error dialog on profile load error.
ProfileErrorCallback(ProfileErrorType type,sql::InitStatus status)37 void ProfileErrorCallback(ProfileErrorType type, sql::InitStatus status) {
38 ShowProfileErrorDialog(
39 type,
40 (status == sql::INIT_FAILURE) ?
41 IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR);
42 }
43
InitSyncableServicesOnDBThread(scoped_refptr<AutofillWebDataService> autofill_web_data,const base::FilePath & profile_path,const std::string & app_locale,autofill::AutofillWebDataBackend * autofill_backend)44 void InitSyncableServicesOnDBThread(
45 scoped_refptr<AutofillWebDataService> autofill_web_data,
46 const base::FilePath& profile_path,
47 const std::string& app_locale,
48 autofill::AutofillWebDataBackend* autofill_backend) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
50
51 // Currently only Autocomplete and Autofill profiles use the new Sync API, but
52 // all the database data should migrate to this API over time.
53 AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
54 autofill_web_data.get(), autofill_backend);
55 AutocompleteSyncableService::FromWebDataService(autofill_web_data.get())
56 ->InjectStartSyncFlare(
57 sync_start_util::GetFlareForSyncableService(profile_path));
58 AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
59 autofill_web_data.get(), autofill_backend, app_locale);
60 AutofillProfileSyncableService::FromWebDataService(autofill_web_data.get())
61 ->InjectStartSyncFlare(
62 sync_start_util::GetFlareForSyncableService(profile_path));
63 }
64
65 } // namespace
66
WebDataServiceWrapper()67 WebDataServiceWrapper::WebDataServiceWrapper() {}
68
WebDataServiceWrapper(Profile * profile)69 WebDataServiceWrapper::WebDataServiceWrapper(Profile* profile) {
70 base::FilePath profile_path = profile->GetPath();
71 base::FilePath path = profile_path.Append(kWebDataFilename);
72
73 scoped_refptr<base::MessageLoopProxy> ui_thread =
74 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
75 scoped_refptr<base::MessageLoopProxy> db_thread =
76 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB);
77 web_database_ = new WebDatabaseService(path, ui_thread, db_thread);
78
79 // All tables objects that participate in managing the database must
80 // be added here.
81 web_database_->AddTable(
82 scoped_ptr<WebDatabaseTable>(new autofill::AutofillTable(
83 g_browser_process->GetApplicationLocale())));
84 web_database_->AddTable(
85 scoped_ptr<WebDatabaseTable>(new KeywordTable()));
86 // TODO(mdm): We only really need the LoginsTable on Windows for IE7 password
87 // access, but for now, we still create it on all platforms since it deletes
88 // the old logins table. We can remove this after a while, e.g. in M22 or so.
89 web_database_->AddTable(
90 scoped_ptr<WebDatabaseTable>(new LoginsTable()));
91 web_database_->AddTable(
92 scoped_ptr<WebDatabaseTable>(new TokenServiceTable()));
93 web_database_->AddTable(
94 scoped_ptr<WebDatabaseTable>(new WebAppsTable()));
95 // TODO(thakis): Add a migration to delete the SQL table used by
96 // WebIntentsTable, then remove this.
97 web_database_->AddTable(
98 scoped_ptr<WebDatabaseTable>(new WebIntentsTable()));
99
100 web_database_->LoadDatabase();
101
102 autofill_web_data_ = new AutofillWebDataService(
103 web_database_, ui_thread, db_thread, base::Bind(
104 &ProfileErrorCallback, PROFILE_ERROR_DB_AUTOFILL_WEB_DATA));
105 autofill_web_data_->Init();
106
107 token_web_data_ = new TokenWebData(
108 web_database_, base::Bind(&ProfileErrorCallback,
109 PROFILE_ERROR_DB_TOKEN_WEB_DATA));
110 token_web_data_->Init();
111
112 web_data_ = new WebDataService(
113 web_database_, base::Bind(&ProfileErrorCallback,
114 PROFILE_ERROR_DB_WEB_DATA));
115 web_data_->Init();
116
117 autofill_web_data_->GetAutofillBackend(
118 base::Bind(&InitSyncableServicesOnDBThread,
119 autofill_web_data_,
120 profile_path,
121 g_browser_process->GetApplicationLocale()));
122 }
123
~WebDataServiceWrapper()124 WebDataServiceWrapper::~WebDataServiceWrapper() {
125 }
126
Shutdown()127 void WebDataServiceWrapper::Shutdown() {
128 autofill_web_data_->ShutdownOnUIThread();
129 token_web_data_->ShutdownOnUIThread();
130 web_data_->ShutdownOnUIThread();
131 web_database_->ShutdownDatabase();
132 }
133
134 scoped_refptr<AutofillWebDataService>
GetAutofillWebData()135 WebDataServiceWrapper::GetAutofillWebData() {
136 return autofill_web_data_.get();
137 }
138
GetWebData()139 scoped_refptr<WebDataService> WebDataServiceWrapper::GetWebData() {
140 return web_data_.get();
141 }
142
GetTokenWebData()143 scoped_refptr<TokenWebData> WebDataServiceWrapper::GetTokenWebData() {
144 return token_web_data_.get();
145 }
146
147 // static
FromBrowserContext(content::BrowserContext * context)148 scoped_refptr<TokenWebData> TokenWebData::FromBrowserContext(
149 content::BrowserContext* context) {
150 // For this service, the implicit/explicit distinction doesn't
151 // really matter; it's just used for a DCHECK. So we currently
152 // cheat and always say EXPLICIT_ACCESS.
153 WebDataServiceWrapper* wrapper =
154 WebDataServiceFactory::GetForProfile(
155 static_cast<Profile*>(context), Profile::EXPLICIT_ACCESS);
156 if (wrapper)
157 return wrapper->GetTokenWebData();
158 // |wrapper| can be NULL in Incognito mode.
159 return scoped_refptr<TokenWebData>(NULL);
160 }
161
162 // static
FromBrowserContext(content::BrowserContext * context)163 scoped_refptr<WebDataService> WebDataService::FromBrowserContext(
164 content::BrowserContext* context) {
165 // For this service, the implicit/explicit distinction doesn't
166 // really matter; it's just used for a DCHECK. So we currently
167 // cheat and always say EXPLICIT_ACCESS.
168 WebDataServiceWrapper* wrapper =
169 WebDataServiceFactory::GetForProfile(
170 static_cast<Profile*>(context), Profile::EXPLICIT_ACCESS);
171 if (wrapper)
172 return wrapper->GetWebData();
173 // |wrapper| can be NULL in Incognito mode.
174 return scoped_refptr<WebDataService>(NULL);
175 }
176
WebDataServiceFactory()177 WebDataServiceFactory::WebDataServiceFactory()
178 : BrowserContextKeyedServiceFactory(
179 "WebDataService",
180 BrowserContextDependencyManager::GetInstance()) {
181 // WebDataServiceFactory has no dependecies.
182 }
183
~WebDataServiceFactory()184 WebDataServiceFactory::~WebDataServiceFactory() {}
185
186 // static
GetForProfile(Profile * profile,Profile::ServiceAccessType access_type)187 WebDataServiceWrapper* WebDataServiceFactory::GetForProfile(
188 Profile* profile,
189 Profile::ServiceAccessType access_type) {
190 // If |access_type| starts being used for anything other than this
191 // DCHECK, we need to start taking it as a parameter to
192 // the *WebDataService::FromBrowserContext() functions (see above).
193 DCHECK(access_type != Profile::IMPLICIT_ACCESS || !profile->IsOffTheRecord());
194 return static_cast<WebDataServiceWrapper*>(
195 GetInstance()->GetServiceForBrowserContext(profile, true));
196 }
197
198 // static
GetForProfileIfExists(Profile * profile,Profile::ServiceAccessType access_type)199 WebDataServiceWrapper* WebDataServiceFactory::GetForProfileIfExists(
200 Profile* profile,
201 Profile::ServiceAccessType access_type) {
202 // If |access_type| starts being used for anything other than this
203 // DCHECK, we need to start taking it as a parameter to
204 // the *WebDataService::FromBrowserContext() functions (see above).
205 DCHECK(access_type != Profile::IMPLICIT_ACCESS || !profile->IsOffTheRecord());
206 return static_cast<WebDataServiceWrapper*>(
207 GetInstance()->GetServiceForBrowserContext(profile, false));
208 }
209
210 // static
211 scoped_refptr<AutofillWebDataService>
GetAutofillWebDataForProfile(Profile * profile,Profile::ServiceAccessType access_type)212 WebDataServiceFactory::GetAutofillWebDataForProfile(
213 Profile* profile,
214 Profile::ServiceAccessType access_type) {
215 WebDataServiceWrapper* wrapper =
216 WebDataServiceFactory::GetForProfile(profile, access_type);
217 // |wrapper| can be NULL in Incognito mode.
218 return wrapper ?
219 wrapper->GetAutofillWebData() :
220 scoped_refptr<AutofillWebDataService>(NULL);
221 }
222
223 // static
GetInstance()224 WebDataServiceFactory* WebDataServiceFactory::GetInstance() {
225 return Singleton<WebDataServiceFactory>::get();
226 }
227
GetBrowserContextToUse(content::BrowserContext * context) const228 content::BrowserContext* WebDataServiceFactory::GetBrowserContextToUse(
229 content::BrowserContext* context) const {
230 return chrome::GetBrowserContextRedirectedInIncognito(context);
231 }
232
BuildServiceInstanceFor(content::BrowserContext * profile) const233 BrowserContextKeyedService* WebDataServiceFactory::BuildServiceInstanceFor(
234 content::BrowserContext* profile) const {
235 return new WebDataServiceWrapper(static_cast<Profile*>(profile));
236 }
237
ServiceIsNULLWhileTesting() const238 bool WebDataServiceFactory::ServiceIsNULLWhileTesting() const {
239 return true;
240 }
241