Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: chrome/browser/webdata/web_data_service_factory.cc

Issue 364343002: Kill WebDataService, move (WIN only) Password code into separate class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments and clean up Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/webdata/web_data_service_factory.h" 5 #include "chrome/browser/webdata/web_data_service_factory.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/files/file_path.h" 8 #include "base/files/file_path.h"
9 #include "chrome/browser/browser_process.h" 9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/profiles/incognito_helpers.h" 10 #include "chrome/browser/profiles/incognito_helpers.h"
11 #include "chrome/browser/sync/glue/sync_start_util.h" 11 #include "chrome/browser/sync/glue/sync_start_util.h"
12 #include "chrome/browser/ui/profile_error_dialog.h" 12 #include "chrome/browser/ui/profile_error_dialog.h"
13 #include "chrome/browser/webdata/autocomplete_syncable_service.h" 13 #include "chrome/browser/webdata/autocomplete_syncable_service.h"
14 #include "chrome/browser/webdata/logins_table.h" 14 #include "chrome/browser/webdata/logins_table.h"
15 #include "chrome/browser/webdata/web_apps_table.h" 15 #include "chrome/browser/webdata/web_apps_table.h"
16 #include "chrome/browser/webdata/web_data_service.h"
17 #include "chrome/browser/webdata/web_intents_table.h" 16 #include "chrome/browser/webdata/web_intents_table.h"
18 #include "components/autofill/core/browser/autofill_country.h" 17 #include "components/autofill/core/browser/autofill_country.h"
19 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_ser vice.h" 18 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_ser vice.h"
20 #include "components/autofill/core/browser/webdata/autofill_table.h" 19 #include "components/autofill/core/browser/webdata/autofill_table.h"
21 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" 20 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
22 #include "components/keyed_service/content/browser_context_dependency_manager.h" 21 #include "components/keyed_service/content/browser_context_dependency_manager.h"
23 #include "components/search_engines/keyword_table.h" 22 #include "components/search_engines/keyword_table.h"
24 #include "components/search_engines/keyword_web_data_service.h" 23 #include "components/search_engines/keyword_web_data_service.h"
25 #include "components/signin/core/browser/webdata/token_service_table.h" 24 #include "components/signin/core/browser/webdata/token_service_table.h"
26 #include "components/signin/core/browser/webdata/token_web_data.h" 25 #include "components/signin/core/browser/webdata/token_web_data.h"
27 #include "components/webdata/common/webdata_constants.h" 26 #include "components/webdata/common/webdata_constants.h"
28 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
29 #include "grit/chromium_strings.h" 28 #include "grit/chromium_strings.h"
30 #include "grit/generated_resources.h" 29 #include "grit/generated_resources.h"
31 30
31 #if defined(OS_WIN)
32 #include "chrome/browser/webdata/password_web_data_service_win.h"
33 #endif
34
32 using autofill::AutofillWebDataService; 35 using autofill::AutofillWebDataService;
33 using autofill::AutofillProfileSyncableService; 36 using autofill::AutofillProfileSyncableService;
34 using content::BrowserThread; 37 using content::BrowserThread;
35 38
36 namespace { 39 namespace {
37 40
38 // Callback to show error dialog on profile load error. 41 // Callback to show error dialog on profile load error.
39 void ProfileErrorCallback(ProfileErrorType type, sql::InitStatus status) { 42 void ProfileErrorCallback(ProfileErrorType type, sql::InitStatus status) {
40 ShowProfileErrorDialog( 43 ShowProfileErrorDialog(
41 type, 44 type,
42 (status == sql::INIT_FAILURE) ? 45 (status == sql::INIT_FAILURE) ?
43 IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR); 46 IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR);
44 } 47 }
45 48
46 void InitSyncableServicesOnDBThread( 49 void InitSyncableServicesOnDBThread(
47 scoped_refptr<AutofillWebDataService> autofill_web_data, 50 scoped_refptr<AutofillWebDataService> autofill_web_data,
48 const base::FilePath& profile_path, 51 const base::FilePath& profile_path,
49 const std::string& app_locale, 52 const std::string& app_locale,
50 autofill::AutofillWebDataBackend* autofill_backend) { 53 autofill::AutofillWebDataBackend* autofill_backend) {
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
52 55
53 // Currently only Autocomplete and Autofill profiles use the new Sync API, but 56 // Currently only Autocomplete and Autofill profiles use the new Sync API, but
54 // all the database data should migrate to this API over time. 57 // all the database data should migrate to this API over time.
55 AutocompleteSyncableService::CreateForWebDataServiceAndBackend( 58 AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
56 autofill_web_data.get(), autofill_backend); 59 autofill_web_data.get(), autofill_backend);
57 AutocompleteSyncableService::FromWebDataService(autofill_web_data.get()) 60 AutocompleteSyncableService::FromWebDataService(autofill_web_data.get())
58 ->InjectStartSyncFlare( 61 ->InjectStartSyncFlare(
59 sync_start_util::GetFlareForSyncableService(profile_path)); 62 sync_start_util::GetFlareForSyncableService(profile_path));
60 AutofillProfileSyncableService::CreateForWebDataServiceAndBackend( 63 AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
61 autofill_web_data.get(), autofill_backend, app_locale); 64 autofill_web_data.get(), autofill_backend, app_locale);
62 AutofillProfileSyncableService::FromWebDataService(autofill_web_data.get()) 65 AutofillProfileSyncableService::FromWebDataService(autofill_web_data.get())
63 ->InjectStartSyncFlare( 66 ->InjectStartSyncFlare(
64 sync_start_util::GetFlareForSyncableService(profile_path)); 67 sync_start_util::GetFlareForSyncableService(profile_path));
65 } 68 }
66 69
67 } // namespace 70 } // namespace
68 71
69 WebDataServiceWrapper::WebDataServiceWrapper() {} 72 WebDataServiceWrapper::WebDataServiceWrapper() {
73 }
70 74
71 WebDataServiceWrapper::WebDataServiceWrapper(Profile* profile) { 75 WebDataServiceWrapper::WebDataServiceWrapper(Profile* profile) {
72 base::FilePath profile_path = profile->GetPath(); 76 base::FilePath profile_path = profile->GetPath();
73 base::FilePath path = profile_path.Append(kWebDataFilename); 77 base::FilePath path = profile_path.Append(kWebDataFilename);
74 78
75 scoped_refptr<base::MessageLoopProxy> ui_thread = 79 scoped_refptr<base::MessageLoopProxy> ui_thread =
76 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); 80 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
77 scoped_refptr<base::MessageLoopProxy> db_thread = 81 scoped_refptr<base::MessageLoopProxy> db_thread =
78 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB); 82 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB);
79 web_database_ = new WebDatabaseService(path, ui_thread, db_thread); 83 web_database_ = new WebDatabaseService(path, ui_thread, db_thread);
80 84
81 // All tables objects that participate in managing the database must 85 // All tables objects that participate in managing the database must
82 // be added here. 86 // be added here.
83 web_database_->AddTable( 87 web_database_->AddTable(scoped_ptr<WebDatabaseTable>(
84 scoped_ptr<WebDatabaseTable>(new autofill::AutofillTable( 88 new autofill::AutofillTable(g_browser_process->GetApplicationLocale())));
85 g_browser_process->GetApplicationLocale()))); 89 web_database_->AddTable(scoped_ptr<WebDatabaseTable>(new KeywordTable()));
86 web_database_->AddTable(
87 scoped_ptr<WebDatabaseTable>(new KeywordTable()));
88 // TODO(mdm): We only really need the LoginsTable on Windows for IE7 password 90 // TODO(mdm): We only really need the LoginsTable on Windows for IE7 password
89 // access, but for now, we still create it on all platforms since it deletes 91 // access, but for now, we still create it on all platforms since it deletes
90 // the old logins table. We can remove this after a while, e.g. in M22 or so. 92 // the old logins table. We can remove this after a while, e.g. in M22 or so.
91 web_database_->AddTable( 93 web_database_->AddTable(scoped_ptr<WebDatabaseTable>(new LoginsTable()));
92 scoped_ptr<WebDatabaseTable>(new LoginsTable()));
93 web_database_->AddTable( 94 web_database_->AddTable(
94 scoped_ptr<WebDatabaseTable>(new TokenServiceTable())); 95 scoped_ptr<WebDatabaseTable>(new TokenServiceTable()));
95 web_database_->AddTable( 96 // TODO(caitkp): Add a migration to delete the SQL table used by
96 scoped_ptr<WebDatabaseTable>(new WebAppsTable())); 97 // WebIntentsTable, then remove this.
98 web_database_->AddTable(scoped_ptr<WebDatabaseTable>(new WebAppsTable()));
97 // TODO(thakis): Add a migration to delete the SQL table used by 99 // TODO(thakis): Add a migration to delete the SQL table used by
98 // WebIntentsTable, then remove this. 100 // WebIntentsTable, then remove this.
99 web_database_->AddTable( 101 web_database_->AddTable(scoped_ptr<WebDatabaseTable>(new WebIntentsTable()));
100 scoped_ptr<WebDatabaseTable>(new WebIntentsTable()));
101 102
102 web_database_->LoadDatabase(); 103 web_database_->LoadDatabase();
103 104
104 autofill_web_data_ = new AutofillWebDataService( 105 autofill_web_data_ = new AutofillWebDataService(
105 web_database_, ui_thread, db_thread, base::Bind( 106 web_database_,
106 &ProfileErrorCallback, PROFILE_ERROR_DB_AUTOFILL_WEB_DATA)); 107 ui_thread,
108 db_thread,
109 base::Bind(&ProfileErrorCallback, PROFILE_ERROR_DB_AUTOFILL_WEB_DATA));
107 autofill_web_data_->Init(); 110 autofill_web_data_->Init();
108 111
109 keyword_web_data_ = new KeywordWebDataService( 112 keyword_web_data_ = new KeywordWebDataService(
110 web_database_, ui_thread, base::Bind( 113 web_database_,
111 &ProfileErrorCallback, PROFILE_ERROR_DB_KEYWORD_WEB_DATA)); 114 ui_thread,
115 base::Bind(&ProfileErrorCallback, PROFILE_ERROR_DB_KEYWORD_WEB_DATA));
112 keyword_web_data_->Init(); 116 keyword_web_data_->Init();
113 117
114 token_web_data_ = new TokenWebData( 118 token_web_data_ = new TokenWebData(
115 web_database_, ui_thread, db_thread, base::Bind( 119 web_database_,
116 &ProfileErrorCallback, PROFILE_ERROR_DB_TOKEN_WEB_DATA)); 120 ui_thread,
121 db_thread,
122 base::Bind(&ProfileErrorCallback, PROFILE_ERROR_DB_TOKEN_WEB_DATA));
117 token_web_data_->Init(); 123 token_web_data_->Init();
118 124
119 web_data_ = new WebDataService( 125 #if defined(OS_WIN)
120 web_database_, base::Bind(&ProfileErrorCallback, 126 password_web_data_ = new PasswordWebDataService(
121 PROFILE_ERROR_DB_WEB_DATA)); 127 web_database_,
122 web_data_->Init(); 128 base::Bind(&ProfileErrorCallback, PROFILE_ERROR_DB_WEB_DATA));
129 password_web_data_->Init();
130 #endif
123 131
124 autofill_web_data_->GetAutofillBackend( 132 autofill_web_data_->GetAutofillBackend(
125 base::Bind(&InitSyncableServicesOnDBThread, 133 base::Bind(&InitSyncableServicesOnDBThread,
126 autofill_web_data_, 134 autofill_web_data_,
127 profile_path, 135 profile_path,
128 g_browser_process->GetApplicationLocale())); 136 g_browser_process->GetApplicationLocale()));
129 } 137 }
130 138
131 WebDataServiceWrapper::~WebDataServiceWrapper() { 139 WebDataServiceWrapper::~WebDataServiceWrapper() {
132 } 140 }
133 141
134 void WebDataServiceWrapper::Shutdown() { 142 void WebDataServiceWrapper::Shutdown() {
135 autofill_web_data_->ShutdownOnUIThread(); 143 autofill_web_data_->ShutdownOnUIThread();
136 keyword_web_data_->ShutdownOnUIThread(); 144 keyword_web_data_->ShutdownOnUIThread();
137 token_web_data_->ShutdownOnUIThread(); 145 token_web_data_->ShutdownOnUIThread();
138 web_data_->ShutdownOnUIThread(); 146
147 #if defined(OS_WIN)
148 password_web_data_->ShutdownOnUIThread();
149 #endif
139 web_database_->ShutdownDatabase(); 150 web_database_->ShutdownDatabase();
140 } 151 }
141 152
142 scoped_refptr<AutofillWebDataService> 153 scoped_refptr<AutofillWebDataService>
143 WebDataServiceWrapper::GetAutofillWebData() { 154 WebDataServiceWrapper::GetAutofillWebData() {
144 return autofill_web_data_.get(); 155 return autofill_web_data_.get();
145 } 156 }
146 157
147 scoped_refptr<KeywordWebDataService> 158 scoped_refptr<KeywordWebDataService>
148 WebDataServiceWrapper::GetKeywordWebData() { 159 WebDataServiceWrapper::GetKeywordWebData() {
149 return keyword_web_data_.get(); 160 return keyword_web_data_.get();
150 } 161 }
151 162
152 scoped_refptr<WebDataService> WebDataServiceWrapper::GetWebData() {
153 return web_data_.get();
154 }
155
156 scoped_refptr<TokenWebData> WebDataServiceWrapper::GetTokenWebData() { 163 scoped_refptr<TokenWebData> WebDataServiceWrapper::GetTokenWebData() {
157 return token_web_data_.get(); 164 return token_web_data_.get();
158 } 165 }
159 166
160 // static 167 #if defined(OS_WIN)
161 scoped_refptr<WebDataService> WebDataService::FromBrowserContext( 168 scoped_refptr<PasswordWebDataService>
162 content::BrowserContext* context) { 169 WebDataServiceWrapper::GetPasswordWebData() {
163 // For this service, the implicit/explicit distinction doesn't 170 return password_web_data_.get();
164 // really matter; it's just used for a DCHECK. So we currently
165 // cheat and always say EXPLICIT_ACCESS.
166 WebDataServiceWrapper* wrapper =
167 WebDataServiceFactory::GetForProfile(
168 static_cast<Profile*>(context), Profile::EXPLICIT_ACCESS);
169 if (wrapper)
170 return wrapper->GetWebData();
171 // |wrapper| can be NULL in Incognito mode.
172 return scoped_refptr<WebDataService>(NULL);
173 } 171 }
172 #endif
174 173
175 WebDataServiceFactory::WebDataServiceFactory() 174 WebDataServiceFactory::WebDataServiceFactory()
176 : BrowserContextKeyedServiceFactory( 175 : BrowserContextKeyedServiceFactory(
177 "WebDataService", 176 "WebDataService",
178 BrowserContextDependencyManager::GetInstance()) { 177 BrowserContextDependencyManager::GetInstance()) {
179 // WebDataServiceFactory has no dependecies. 178 // WebDataServiceFactory has no dependecies.
180 } 179 }
181 180
182 WebDataServiceFactory::~WebDataServiceFactory() {} 181 WebDataServiceFactory::~WebDataServiceFactory() {
182 }
183 183
184 // static 184 // static
185 WebDataServiceWrapper* WebDataServiceFactory::GetForProfile( 185 WebDataServiceWrapper* WebDataServiceFactory::GetForProfile(
186 Profile* profile, 186 Profile* profile,
187 Profile::ServiceAccessType access_type) { 187 Profile::ServiceAccessType access_type) {
188 // If |access_type| starts being used for anything other than this 188 // If |access_type| starts being used for anything other than this
189 // DCHECK, we need to start taking it as a parameter to 189 // DCHECK, we need to start taking it as a parameter to
190 // the *WebDataService::FromBrowserContext() functions (see above). 190 // the *WebDataService::FromBrowserContext() functions (see above).
191 DCHECK(access_type != Profile::IMPLICIT_ACCESS || !profile->IsOffTheRecord()); 191 DCHECK(access_type != Profile::IMPLICIT_ACCESS || !profile->IsOffTheRecord());
192 return static_cast<WebDataServiceWrapper*>( 192 return static_cast<WebDataServiceWrapper*>(
193 GetInstance()->GetServiceForBrowserContext(profile, true)); 193 GetInstance()->GetServiceForBrowserContext(profile, true));
194 } 194 }
195 195
196 // static 196 // static
197 WebDataServiceWrapper* WebDataServiceFactory::GetForProfileIfExists( 197 WebDataServiceWrapper* WebDataServiceFactory::GetForProfileIfExists(
198 Profile* profile, 198 Profile* profile,
199 Profile::ServiceAccessType access_type) { 199 Profile::ServiceAccessType access_type) {
200 // If |access_type| starts being used for anything other than this 200 // If |access_type| starts being used for anything other than this
201 // DCHECK, we need to start taking it as a parameter to 201 // DCHECK, we need to start taking it as a parameter to
202 // the *WebDataService::FromBrowserContext() functions (see above). 202 // the *WebDataService::FromBrowserContext() functions (see above).
203 DCHECK(access_type != Profile::IMPLICIT_ACCESS || !profile->IsOffTheRecord()); 203 DCHECK(access_type != Profile::IMPLICIT_ACCESS || !profile->IsOffTheRecord());
204 return static_cast<WebDataServiceWrapper*>( 204 return static_cast<WebDataServiceWrapper*>(
205 GetInstance()->GetServiceForBrowserContext(profile, false)); 205 GetInstance()->GetServiceForBrowserContext(profile, false));
206 } 206 }
207 207
208 // static 208 // static
209 scoped_refptr<AutofillWebDataService> 209 scoped_refptr<AutofillWebDataService>
210 WebDataServiceFactory::GetAutofillWebDataForProfile( 210 WebDataServiceFactory::GetAutofillWebDataForProfile(
211 Profile* profile, 211 Profile* profile,
212 Profile::ServiceAccessType access_type) { 212 Profile::ServiceAccessType access_type) {
213 WebDataServiceWrapper* wrapper = 213 WebDataServiceWrapper* wrapper =
214 WebDataServiceFactory::GetForProfile(profile, access_type); 214 WebDataServiceFactory::GetForProfile(profile, access_type);
215 // |wrapper| can be NULL in Incognito mode. 215 // |wrapper| can be NULL in Incognito mode.
216 return wrapper ? 216 return wrapper ?
217 wrapper->GetAutofillWebData() : 217 wrapper->GetAutofillWebData() :
218 scoped_refptr<AutofillWebDataService>(NULL); 218 scoped_refptr<AutofillWebDataService>(NULL);
219 } 219 }
220 220
221 // static 221 // static
222 scoped_refptr<KeywordWebDataService> 222 scoped_refptr<KeywordWebDataService>
223 WebDataServiceFactory::GetKeywordWebDataForProfile( 223 WebDataServiceFactory::GetKeywordWebDataForProfile(
224 Profile* profile, 224 Profile* profile,
225 Profile::ServiceAccessType access_type) { 225 Profile::ServiceAccessType access_type) {
226 WebDataServiceWrapper* wrapper = 226 WebDataServiceWrapper* wrapper =
227 WebDataServiceFactory::GetForProfile(profile, access_type); 227 WebDataServiceFactory::GetForProfile(profile, access_type);
228 // |wrapper| can be NULL in Incognito mode. 228 // |wrapper| can be NULL in Incognito mode.
229 return wrapper ? 229 return wrapper ?
230 wrapper->GetKeywordWebData() : scoped_refptr<KeywordWebDataService>(NULL); 230 wrapper->GetKeywordWebData() : scoped_refptr<KeywordWebDataService>(NULL);
231 } 231 }
232 232
233 // static 233 // static
234 scoped_refptr<TokenWebData> 234 scoped_refptr<TokenWebData> WebDataServiceFactory::GetTokenWebDataForProfile(
235 WebDataServiceFactory::GetTokenWebDataForProfile(
236 Profile* profile, 235 Profile* profile,
237 Profile::ServiceAccessType access_type) { 236 Profile::ServiceAccessType access_type) {
238 WebDataServiceWrapper* wrapper = 237 WebDataServiceWrapper* wrapper =
239 WebDataServiceFactory::GetForProfile(profile, access_type); 238 WebDataServiceFactory::GetForProfile(profile, access_type);
240 // |wrapper| can be NULL in Incognito mode. 239 // |wrapper| can be NULL in Incognito mode.
241 return wrapper ? wrapper->GetTokenWebData() 240 return wrapper ?
242 : scoped_refptr<TokenWebData>(NULL); 241 wrapper->GetTokenWebData() : scoped_refptr<TokenWebData>(NULL);
243 } 242 }
244 243
244 #if defined(OS_WIN)
245 // static
246 scoped_refptr<PasswordWebDataService>
247 WebDataServiceFactory::GetPasswordWebDataForProfile(
248 Profile* profile,
249 Profile::ServiceAccessType access_type) {
250 WebDataServiceWrapper* wrapper =
251 WebDataServiceFactory::GetForProfile(profile, access_type);
252 // |wrapper| can be NULL in Incognito mode.
253 return wrapper ?
254 wrapper->GetPasswordWebData() :
255 scoped_refptr<PasswordWebDataService>(NULL);
256 }
257 #endif
258
245 // static 259 // static
246 WebDataServiceFactory* WebDataServiceFactory::GetInstance() { 260 WebDataServiceFactory* WebDataServiceFactory::GetInstance() {
247 return Singleton<WebDataServiceFactory>::get(); 261 return Singleton<WebDataServiceFactory>::get();
248 } 262 }
249 263
250 content::BrowserContext* WebDataServiceFactory::GetBrowserContextToUse( 264 content::BrowserContext* WebDataServiceFactory::GetBrowserContextToUse(
251 content::BrowserContext* context) const { 265 content::BrowserContext* context) const {
252 return chrome::GetBrowserContextRedirectedInIncognito(context); 266 return chrome::GetBrowserContextRedirectedInIncognito(context);
253 } 267 }
254 268
255 KeyedService* WebDataServiceFactory::BuildServiceInstanceFor( 269 KeyedService* WebDataServiceFactory::BuildServiceInstanceFor(
256 content::BrowserContext* profile) const { 270 content::BrowserContext* profile) const {
257 return new WebDataServiceWrapper(static_cast<Profile*>(profile)); 271 return new WebDataServiceWrapper(static_cast<Profile*>(profile));
258 } 272 }
259 273
260 bool WebDataServiceFactory::ServiceIsNULLWhileTesting() const { 274 bool WebDataServiceFactory::ServiceIsNULLWhileTesting() const {
261 return true; 275 return true;
262 } 276 }
OLDNEW
« no previous file with comments | « chrome/browser/webdata/web_data_service_factory.h ('k') | chrome/browser/webdata/web_data_service_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698