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