Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / safe_browsing / safe_browsing_service.cc
bloba01305c46a0aef1277ecc3c05270b0abb1341e75
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.
5 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/debug/leak_tracker.h"
14 #include "base/lazy_instance.h"
15 #include "base/path_service.h"
16 #include "base/prefs/pref_change_registrar.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_util.h"
20 #include "base/threading/thread.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
28 #include "chrome/browser/safe_browsing/database_manager.h"
29 #include "chrome/browser/safe_browsing/download_protection_service.h"
30 #include "chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h"
31 #include "chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h"
32 #include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h"
33 #include "chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.h"
34 #include "chrome/browser/safe_browsing/malware_details.h"
35 #include "chrome/browser/safe_browsing/ping_manager.h"
36 #include "chrome/browser/safe_browsing/protocol_manager.h"
37 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
38 #include "chrome/browser/safe_browsing/ui_manager.h"
39 #include "chrome/common/chrome_constants.h"
40 #include "chrome/common/chrome_paths.h"
41 #include "chrome/common/chrome_switches.h"
42 #include "chrome/common/pref_names.h"
43 #include "chrome/common/url_constants.h"
44 #include "components/metrics/metrics_service.h"
45 #include "components/startup_metric_utils/startup_metric_utils.h"
46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/cookie_crypto_delegate.h"
48 #include "content/public/browser/cookie_store_factory.h"
49 #include "content/public/browser/notification_service.h"
50 #include "net/cookies/cookie_monster.h"
51 #include "net/url_request/url_request_context.h"
52 #include "net/url_request/url_request_context_getter.h"
54 #if defined(OS_WIN)
55 #include "chrome/installer/util/browser_distribution.h"
56 #endif
58 #if defined(OS_ANDROID)
59 #include <string>
60 #include "base/metrics/field_trial.h"
61 #endif
63 using content::BrowserThread;
65 namespace {
67 // Filename suffix for the cookie database.
68 const base::FilePath::CharType kCookiesFile[] = FILE_PATH_LITERAL(" Cookies");
70 // The default URL prefix where browser fetches chunk updates, hashes,
71 // and reports safe browsing hits and malware details.
72 const char* const kSbDefaultURLPrefix =
73 "https://safebrowsing.google.com/safebrowsing";
75 // The backup URL prefix used when there are issues establishing a connection
76 // with the server at the primary URL.
77 const char* const kSbBackupConnectErrorURLPrefix =
78 "https://alt1-safebrowsing.google.com/safebrowsing";
80 // The backup URL prefix used when there are HTTP-specific issues with the
81 // server at the primary URL.
82 const char* const kSbBackupHttpErrorURLPrefix =
83 "https://alt2-safebrowsing.google.com/safebrowsing";
85 // The backup URL prefix used when there are local network specific issues.
86 const char* const kSbBackupNetworkErrorURLPrefix =
87 "https://alt3-safebrowsing.google.com/safebrowsing";
89 base::FilePath CookieFilePath() {
90 return base::FilePath(
91 SafeBrowsingService::GetBaseFilename().value() + kCookiesFile);
94 #if defined(FULL_SAFE_BROWSING)
95 // Returns true if the incident reporting service is enabled via a field trial.
96 bool IsIncidentReportingServiceEnabled() {
97 const std::string group_name = base::FieldTrialList::FindFullName(
98 "SafeBrowsingIncidentReportingService");
99 return group_name == "Enabled";
101 #endif // defined(FULL_SAFE_BROWSING)
103 } // namespace
105 class SafeBrowsingURLRequestContextGetter
106 : public net::URLRequestContextGetter {
107 public:
108 explicit SafeBrowsingURLRequestContextGetter(
109 SafeBrowsingService* sb_service_);
111 // Implementation for net::UrlRequestContextGetter.
112 virtual net::URLRequestContext* GetURLRequestContext() override;
113 virtual scoped_refptr<base::SingleThreadTaskRunner>
114 GetNetworkTaskRunner() const override;
116 protected:
117 virtual ~SafeBrowsingURLRequestContextGetter();
119 private:
120 SafeBrowsingService* const sb_service_; // Owned by BrowserProcess.
121 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
123 base::debug::LeakTracker<SafeBrowsingURLRequestContextGetter> leak_tracker_;
126 SafeBrowsingURLRequestContextGetter::SafeBrowsingURLRequestContextGetter(
127 SafeBrowsingService* sb_service)
128 : sb_service_(sb_service),
129 network_task_runner_(
130 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)) {
133 SafeBrowsingURLRequestContextGetter::~SafeBrowsingURLRequestContextGetter() {}
135 net::URLRequestContext*
136 SafeBrowsingURLRequestContextGetter::GetURLRequestContext() {
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
138 DCHECK(sb_service_->url_request_context_.get());
140 return sb_service_->url_request_context_.get();
143 scoped_refptr<base::SingleThreadTaskRunner>
144 SafeBrowsingURLRequestContextGetter::GetNetworkTaskRunner() const {
145 return network_task_runner_;
148 // static
149 SafeBrowsingServiceFactory* SafeBrowsingService::factory_ = NULL;
151 // The default SafeBrowsingServiceFactory. Global, made a singleton so we
152 // don't leak it.
153 class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
154 public:
155 virtual SafeBrowsingService* CreateSafeBrowsingService() override {
156 return new SafeBrowsingService();
159 private:
160 friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>;
162 SafeBrowsingServiceFactoryImpl() { }
164 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl);
167 static base::LazyInstance<SafeBrowsingServiceFactoryImpl>::Leaky
168 g_safe_browsing_service_factory_impl = LAZY_INSTANCE_INITIALIZER;
170 // static
171 base::FilePath SafeBrowsingService::GetCookieFilePathForTesting() {
172 return CookieFilePath();
175 // static
176 base::FilePath SafeBrowsingService::GetBaseFilename() {
177 base::FilePath path;
178 bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
179 DCHECK(result);
180 return path.Append(chrome::kSafeBrowsingBaseFilename);
184 // static
185 SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() {
186 if (!factory_)
187 factory_ = g_safe_browsing_service_factory_impl.Pointer();
188 return factory_->CreateSafeBrowsingService();
191 #if defined(OS_ANDROID) && defined(FULL_SAFE_BROWSING)
192 // static
193 bool SafeBrowsingService::IsEnabledByFieldTrial() {
194 const std::string experiment_name =
195 base::FieldTrialList::FindFullName("SafeBrowsingAndroid");
196 return experiment_name == "Enabled";
198 #endif
200 SafeBrowsingService::SafeBrowsingService()
201 : protocol_manager_(NULL),
202 ping_manager_(NULL),
203 enabled_(false) {
206 SafeBrowsingService::~SafeBrowsingService() {
207 // We should have already been shut down. If we're still enabled, then the
208 // database isn't going to be closed properly, which could lead to corruption.
209 DCHECK(!enabled_);
212 void SafeBrowsingService::Initialize() {
213 startup_metric_utils::ScopedSlowStartupUMA
214 scoped_timer("Startup.SlowStartupSafeBrowsingServiceInitialize");
216 url_request_context_getter_ =
217 new SafeBrowsingURLRequestContextGetter(this);
219 ui_manager_ = CreateUIManager();
221 database_manager_ = CreateDatabaseManager();
223 BrowserThread::PostTask(
224 BrowserThread::IO, FROM_HERE,
225 base::Bind(
226 &SafeBrowsingService::InitURLRequestContextOnIOThread, this,
227 make_scoped_refptr(g_browser_process->system_request_context())));
229 #if defined(FULL_SAFE_BROWSING)
230 #if !defined(OS_ANDROID)
231 if (!CommandLine::ForCurrentProcess()->HasSwitch(
232 switches::kDisableClientSidePhishingDetection)) {
233 csd_service_.reset(safe_browsing::ClientSideDetectionService::Create(
234 url_request_context_getter_.get()));
236 download_service_.reset(new safe_browsing::DownloadProtectionService(
237 this, url_request_context_getter_.get()));
238 #endif
240 if (IsIncidentReportingServiceEnabled()) {
241 incident_service_.reset(new safe_browsing::IncidentReportingService(
242 this, url_request_context_getter_));
244 #endif
246 // Track the safe browsing preference of existing profiles.
247 // The SafeBrowsingService will be started if any existing profile has the
248 // preference enabled. It will also listen for updates to the preferences.
249 ProfileManager* profile_manager = g_browser_process->profile_manager();
250 if (profile_manager) {
251 std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
252 for (size_t i = 0; i < profiles.size(); ++i) {
253 if (profiles[i]->IsOffTheRecord())
254 continue;
255 AddPrefService(profiles[i]->GetPrefs());
259 // Track profile creation and destruction.
260 prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
261 content::NotificationService::AllSources());
262 prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
263 content::NotificationService::AllSources());
265 #if defined(FULL_SAFE_BROWSING)
266 // Register all the delayed analysis to the incident reporting service.
267 RegisterAllDelayedAnalysis();
268 #endif
271 void SafeBrowsingService::ShutDown() {
272 // Deletes the PrefChangeRegistrars, whose dtors also unregister |this| as an
273 // observer of the preferences.
274 STLDeleteValues(&prefs_map_);
276 // Remove Profile creation/destruction observers.
277 prefs_registrar_.RemoveAll();
279 Stop(true);
280 // The IO thread is going away, so make sure the ClientSideDetectionService
281 // dtor executes now since it may call the dtor of URLFetcher which relies
282 // on it.
283 csd_service_.reset();
284 download_service_.reset();
285 incident_service_.reset();
287 url_request_context_getter_ = NULL;
288 BrowserThread::PostNonNestableTask(
289 BrowserThread::IO, FROM_HERE,
290 base::Bind(&SafeBrowsingService::DestroyURLRequestContextOnIOThread,
291 this));
294 // Binhash verification is only enabled for UMA users for now.
295 bool SafeBrowsingService::DownloadBinHashNeeded() const {
296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
298 #if defined(FULL_SAFE_BROWSING)
299 return (database_manager_->download_protection_enabled() &&
300 ui_manager_->CanReportStats()) ||
301 (download_protection_service() &&
302 download_protection_service()->enabled());
303 #else
304 return false;
305 #endif
308 net::URLRequestContextGetter* SafeBrowsingService::url_request_context() {
309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
310 return url_request_context_getter_.get();
313 const scoped_refptr<SafeBrowsingUIManager>&
314 SafeBrowsingService::ui_manager() const {
315 return ui_manager_;
318 const scoped_refptr<SafeBrowsingDatabaseManager>&
319 SafeBrowsingService::database_manager() const {
320 return database_manager_;
323 SafeBrowsingProtocolManager* SafeBrowsingService::protocol_manager() const {
324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
325 return protocol_manager_;
328 SafeBrowsingPingManager* SafeBrowsingService::ping_manager() const {
329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
330 return ping_manager_;
333 scoped_ptr<TrackedPreferenceValidationDelegate>
334 SafeBrowsingService::CreatePreferenceValidationDelegate(
335 Profile* profile) const {
336 #if defined(FULL_SAFE_BROWSING)
337 if (incident_service_)
338 return incident_service_->CreatePreferenceValidationDelegate(profile);
339 #endif
340 return scoped_ptr<TrackedPreferenceValidationDelegate>();
343 void SafeBrowsingService::RegisterDelayedAnalysisCallback(
344 const safe_browsing::DelayedAnalysisCallback& callback) {
345 #if defined(FULL_SAFE_BROWSING)
346 if (incident_service_)
347 incident_service_->RegisterDelayedAnalysisCallback(callback);
348 #endif
351 SafeBrowsingUIManager* SafeBrowsingService::CreateUIManager() {
352 return new SafeBrowsingUIManager(this);
355 SafeBrowsingDatabaseManager* SafeBrowsingService::CreateDatabaseManager() {
356 #if defined(FULL_SAFE_BROWSING)
357 return new SafeBrowsingDatabaseManager(this);
358 #else
359 return NULL;
360 #endif
363 void SafeBrowsingService::RegisterAllDelayedAnalysis() {
364 safe_browsing::RegisterBinaryIntegrityAnalysis();
365 safe_browsing::RegisterBlacklistLoadAnalysis();
366 safe_browsing::RegisterVariationsSeedSignatureAnalysis();
369 void SafeBrowsingService::InitURLRequestContextOnIOThread(
370 net::URLRequestContextGetter* system_url_request_context_getter) {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
372 DCHECK(!url_request_context_.get());
374 scoped_refptr<net::CookieStore> cookie_store(
375 content::CreateCookieStore(
376 content::CookieStoreConfig(
377 CookieFilePath(),
378 content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
379 NULL,
380 NULL)));
382 url_request_context_.reset(new net::URLRequestContext);
383 // |system_url_request_context_getter| may be NULL during tests.
384 if (system_url_request_context_getter) {
385 url_request_context_->CopyFrom(
386 system_url_request_context_getter->GetURLRequestContext());
388 url_request_context_->set_cookie_store(cookie_store.get());
391 void SafeBrowsingService::DestroyURLRequestContextOnIOThread() {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
394 url_request_context_->AssertNoURLRequests();
396 // Need to do the CheckForLeaks on IOThread instead of in ShutDown where
397 // url_request_context_getter_ is cleared, since the URLRequestContextGetter
398 // will PostTask to IOTread to delete itself.
399 using base::debug::LeakTracker;
400 LeakTracker<SafeBrowsingURLRequestContextGetter>::CheckForLeaks();
402 url_request_context_.reset();
405 SafeBrowsingProtocolConfig SafeBrowsingService::GetProtocolConfig() const {
406 SafeBrowsingProtocolConfig config;
407 // On Windows, get the safe browsing client name from the browser
408 // distribution classes in installer util. These classes don't yet have
409 // an analog on non-Windows builds so just keep the name specified here.
410 #if defined(OS_WIN)
411 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
412 config.client_name = dist->GetSafeBrowsingName();
413 #else
414 #if defined(GOOGLE_CHROME_BUILD)
415 config.client_name = "googlechrome";
416 #else
417 config.client_name = "chromium";
418 #endif
420 // Mark client string to allow server to differentiate mobile.
421 #if defined(OS_ANDROID)
422 config.client_name.append("-a");
423 #elif defined(OS_IOS)
424 config.client_name.append("-i");
425 #endif
427 #endif // defined(OS_WIN)
428 CommandLine* cmdline = CommandLine::ForCurrentProcess();
429 config.disable_auto_update =
430 cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
431 cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
432 config.url_prefix = kSbDefaultURLPrefix;
433 config.backup_connect_error_url_prefix = kSbBackupConnectErrorURLPrefix;
434 config.backup_http_error_url_prefix = kSbBackupHttpErrorURLPrefix;
435 config.backup_network_error_url_prefix = kSbBackupNetworkErrorURLPrefix;
437 return config;
440 void SafeBrowsingService::StartOnIOThread(
441 net::URLRequestContextGetter* url_request_context_getter) {
442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
443 if (enabled_)
444 return;
445 enabled_ = true;
447 SafeBrowsingProtocolConfig config = GetProtocolConfig();
449 #if defined(FULL_SAFE_BROWSING)
450 DCHECK(database_manager_.get());
451 database_manager_->StartOnIOThread();
453 DCHECK(!protocol_manager_);
454 protocol_manager_ = SafeBrowsingProtocolManager::Create(
455 database_manager_.get(), url_request_context_getter, config);
456 protocol_manager_->Initialize();
457 #endif
459 DCHECK(!ping_manager_);
460 ping_manager_ = SafeBrowsingPingManager::Create(
461 url_request_context_getter, config);
464 void SafeBrowsingService::StopOnIOThread(bool shutdown) {
465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
467 #if defined(FULL_SAFE_BROWSING)
468 database_manager_->StopOnIOThread(shutdown);
469 #endif
470 ui_manager_->StopOnIOThread(shutdown);
472 if (enabled_) {
473 enabled_ = false;
475 #if defined(FULL_SAFE_BROWSING)
476 // This cancels all in-flight GetHash requests. Note that database_manager_
477 // relies on the protocol_manager_ so if the latter is destroyed, the
478 // former must be stopped.
479 delete protocol_manager_;
480 protocol_manager_ = NULL;
481 #endif
482 delete ping_manager_;
483 ping_manager_ = NULL;
487 void SafeBrowsingService::Start() {
488 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
490 BrowserThread::PostTask(
491 BrowserThread::IO, FROM_HERE,
492 base::Bind(&SafeBrowsingService::StartOnIOThread, this,
493 url_request_context_getter_));
496 void SafeBrowsingService::Stop(bool shutdown) {
497 BrowserThread::PostTask(
498 BrowserThread::IO, FROM_HERE,
499 base::Bind(&SafeBrowsingService::StopOnIOThread, this, shutdown));
502 void SafeBrowsingService::Observe(int type,
503 const content::NotificationSource& source,
504 const content::NotificationDetails& details) {
505 switch (type) {
506 case chrome::NOTIFICATION_PROFILE_CREATED: {
507 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
508 Profile* profile = content::Source<Profile>(source).ptr();
509 if (!profile->IsOffTheRecord())
510 AddPrefService(profile->GetPrefs());
511 break;
513 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
515 Profile* profile = content::Source<Profile>(source).ptr();
516 if (!profile->IsOffTheRecord())
517 RemovePrefService(profile->GetPrefs());
518 break;
520 default:
521 NOTREACHED();
525 void SafeBrowsingService::AddPrefService(PrefService* pref_service) {
526 DCHECK(prefs_map_.find(pref_service) == prefs_map_.end());
527 PrefChangeRegistrar* registrar = new PrefChangeRegistrar();
528 registrar->Init(pref_service);
529 registrar->Add(prefs::kSafeBrowsingEnabled,
530 base::Bind(&SafeBrowsingService::RefreshState,
531 base::Unretained(this)));
532 prefs_map_[pref_service] = registrar;
533 RefreshState();
536 void SafeBrowsingService::RemovePrefService(PrefService* pref_service) {
537 if (prefs_map_.find(pref_service) != prefs_map_.end()) {
538 delete prefs_map_[pref_service];
539 prefs_map_.erase(pref_service);
540 RefreshState();
541 } else {
542 NOTREACHED();
546 void SafeBrowsingService::RefreshState() {
547 // Check if any profile requires the service to be active.
548 bool enable = false;
549 std::map<PrefService*, PrefChangeRegistrar*>::iterator iter;
550 for (iter = prefs_map_.begin(); iter != prefs_map_.end(); ++iter) {
551 if (iter->first->GetBoolean(prefs::kSafeBrowsingEnabled)) {
552 enable = true;
553 break;
557 if (enable)
558 Start();
559 else
560 Stop(false);
562 #if defined(FULL_SAFE_BROWSING)
563 if (csd_service_)
564 csd_service_->SetEnabledAndRefreshState(enable);
565 if (download_service_)
566 download_service_->SetEnabled(enable);
567 #endif