Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / rlz / rlz.cc
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 // This code glues the RLZ library DLL with Chrome. It allows Chrome to work
6 // with or without the DLL being present. If the DLL is not present the
7 // functions do nothing and just return false.
8
9 #include "chrome/browser/rlz/rlz.h"
10
11 #include <algorithm>
12
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/debug/trace_event.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/google/google_brand.h"
23 #include "chrome/browser/omnibox/omnibox_log.h"
24 #include "chrome/browser/prefs/session_startup_pref.h"
25 #include "chrome/browser/search_engines/template_url_service_factory.h"
26 #include "chrome/browser/ui/startup/startup_browser_creator.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/pref_names.h"
29 #include "components/google/core/browser/google_util.h"
30 #include "components/search_engines/template_url.h"
31 #include "components/search_engines/template_url_service.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/navigation_entry.h"
34 #include "content/public/browser/notification_service.h"
35 #include "net/http/http_util.h"
36
37 #if defined(OS_WIN)
38 #include "chrome/installer/util/google_update_settings.h"
39 #else
40 namespace GoogleUpdateSettings {
41 static bool GetLanguage(base::string16* language) {
42   // TODO(thakis): Implement.
43   NOTIMPLEMENTED();
44   return false;
45 }
46
47 // The referral program is defunct and not used. No need to implement these
48 // functions on non-Win platforms.
49 static bool GetReferral(base::string16* referral) {
50   return true;
51 }
52 static bool ClearReferral() {
53   return true;
54 }
55 }  // namespace GoogleUpdateSettings
56 #endif
57
58 using content::BrowserThread;
59 using content::NavigationEntry;
60
61 namespace {
62
63 // Maximum and minimum delay for financial ping we would allow to be set through
64 // master preferences. Somewhat arbitrary, may need to be adjusted in future.
65 const base::TimeDelta kMaxInitDelay = base::TimeDelta::FromSeconds(200);
66 const base::TimeDelta kMinInitDelay = base::TimeDelta::FromSeconds(20);
67
68 bool IsBrandOrganic(const std::string& brand) {
69   return brand.empty() || google_brand::IsOrganic(brand);
70 }
71
72 void RecordProductEvents(bool first_run,
73                          bool is_google_default_search,
74                          bool is_google_homepage,
75                          bool is_google_in_startpages,
76                          bool already_ran,
77                          bool omnibox_used,
78                          bool homepage_used,
79                          bool app_list_used) {
80   TRACE_EVENT0("RLZ", "RecordProductEvents");
81   // Record the installation of chrome. We call this all the time but the rlz
82   // lib should ignore all but the first one.
83   rlz_lib::RecordProductEvent(rlz_lib::CHROME,
84                               RLZTracker::ChromeOmnibox(),
85                               rlz_lib::INSTALL);
86 #if !defined(OS_IOS)
87   rlz_lib::RecordProductEvent(rlz_lib::CHROME,
88                               RLZTracker::ChromeHomePage(),
89                               rlz_lib::INSTALL);
90   rlz_lib::RecordProductEvent(rlz_lib::CHROME,
91                               RLZTracker::ChromeAppList(),
92                               rlz_lib::INSTALL);
93 #endif  // !defined(OS_IOS)
94
95   if (!already_ran) {
96     // Do the initial event recording if is the first run or if we have an
97     // empty rlz which means we haven't got a chance to do it.
98     char omnibox_rlz[rlz_lib::kMaxRlzLength + 1];
99     if (!rlz_lib::GetAccessPointRlz(RLZTracker::ChromeOmnibox(), omnibox_rlz,
100                                     rlz_lib::kMaxRlzLength)) {
101       omnibox_rlz[0] = 0;
102     }
103
104     // Record if google is the initial search provider and/or home page.
105     if ((first_run || omnibox_rlz[0] == 0) && is_google_default_search) {
106       rlz_lib::RecordProductEvent(rlz_lib::CHROME,
107                                   RLZTracker::ChromeOmnibox(),
108                                   rlz_lib::SET_TO_GOOGLE);
109     }
110
111 #if !defined(OS_IOS)
112     char homepage_rlz[rlz_lib::kMaxRlzLength + 1];
113     if (!rlz_lib::GetAccessPointRlz(RLZTracker::ChromeHomePage(), homepage_rlz,
114                                     rlz_lib::kMaxRlzLength)) {
115       homepage_rlz[0] = 0;
116     }
117
118     if ((first_run || homepage_rlz[0] == 0) &&
119         (is_google_homepage || is_google_in_startpages)) {
120       rlz_lib::RecordProductEvent(rlz_lib::CHROME,
121                                   RLZTracker::ChromeHomePage(),
122                                   rlz_lib::SET_TO_GOOGLE);
123     }
124
125     char app_list_rlz[rlz_lib::kMaxRlzLength + 1];
126     if (!rlz_lib::GetAccessPointRlz(RLZTracker::ChromeAppList(), app_list_rlz,
127                                     rlz_lib::kMaxRlzLength)) {
128       app_list_rlz[0] = 0;
129     }
130
131     // Record if google is the initial search provider and/or home page.
132     if ((first_run || app_list_rlz[0] == 0) && is_google_default_search) {
133       rlz_lib::RecordProductEvent(rlz_lib::CHROME,
134                                   RLZTracker::ChromeAppList(),
135                                   rlz_lib::SET_TO_GOOGLE);
136     }
137 #endif  // !defined(OS_IOS)
138   }
139
140   // Record first user interaction with the omnibox. We call this all the
141   // time but the rlz lib should ingore all but the first one.
142   if (omnibox_used) {
143     rlz_lib::RecordProductEvent(rlz_lib::CHROME,
144                                 RLZTracker::ChromeOmnibox(),
145                                 rlz_lib::FIRST_SEARCH);
146   }
147
148 #if !defined(OS_IOS)
149   // Record first user interaction with the home page. We call this all the
150   // time but the rlz lib should ingore all but the first one.
151   if (homepage_used || is_google_in_startpages) {
152     rlz_lib::RecordProductEvent(rlz_lib::CHROME,
153                                 RLZTracker::ChromeHomePage(),
154                                 rlz_lib::FIRST_SEARCH);
155   }
156
157   // Record first user interaction with the app list. We call this all the
158   // time but the rlz lib should ingore all but the first one.
159   if (app_list_used) {
160     rlz_lib::RecordProductEvent(rlz_lib::CHROME,
161                                 RLZTracker::ChromeAppList(),
162                                 rlz_lib::FIRST_SEARCH);
163   }
164 #endif  // !defined(OS_IOS)
165 }
166
167 bool SendFinancialPing(const std::string& brand,
168                        const base::string16& lang,
169                        const base::string16& referral) {
170   rlz_lib::AccessPoint points[] = {RLZTracker::ChromeOmnibox(),
171 #if !defined(OS_IOS)
172                                    RLZTracker::ChromeHomePage(),
173                                    RLZTracker::ChromeAppList(),
174 #endif
175                                    rlz_lib::NO_ACCESS_POINT};
176   std::string lang_ascii(base::UTF16ToASCII(lang));
177   std::string referral_ascii(base::UTF16ToASCII(referral));
178   std::string product_signature;
179 #if defined(OS_CHROMEOS)
180   product_signature = "chromeos";
181 #else
182   product_signature = "chrome";
183 #endif
184   return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points,
185                                     product_signature.c_str(),
186                                     brand.c_str(), referral_ascii.c_str(),
187                                     lang_ascii.c_str(), false, true);
188 }
189
190 }  // namespace
191
192 RLZTracker* RLZTracker::tracker_ = NULL;
193
194 // static
195 RLZTracker* RLZTracker::GetInstance() {
196   return tracker_ ? tracker_ : Singleton<RLZTracker>::get();
197 }
198
199 RLZTracker::RLZTracker()
200     : first_run_(false),
201       send_ping_immediately_(false),
202       is_google_default_search_(false),
203       is_google_homepage_(false),
204       is_google_in_startpages_(false),
205       worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()),
206       already_ran_(false),
207       omnibox_used_(false),
208       homepage_used_(false),
209       app_list_used_(false),
210       min_init_delay_(kMinInitDelay) {
211 }
212
213 RLZTracker::~RLZTracker() {
214 }
215
216 // static
217 bool RLZTracker::InitRlzDelayed(bool first_run,
218                                 bool send_ping_immediately,
219                                 base::TimeDelta delay,
220                                 bool is_google_default_search,
221                                 bool is_google_homepage,
222                                 bool is_google_in_startpages) {
223   return GetInstance()->Init(first_run, send_ping_immediately, delay,
224                              is_google_default_search, is_google_homepage,
225                              is_google_in_startpages);
226 }
227
228 // static
229 bool RLZTracker::InitRlzFromProfileDelayed(Profile* profile,
230                                            bool first_run,
231                                            bool send_ping_immediately,
232                                            base::TimeDelta delay) {
233   bool is_google_default_search = false;
234   TemplateURLService* template_url_service =
235       TemplateURLServiceFactory::GetForProfile(profile);
236   if (template_url_service) {
237     const TemplateURL* url_template =
238         template_url_service->GetDefaultSearchProvider();
239     is_google_default_search =
240         url_template && url_template->url_ref().HasGoogleBaseURLs(
241             template_url_service->search_terms_data());
242   }
243
244   PrefService* pref_service = profile->GetPrefs();
245   bool is_google_homepage = google_util::IsGoogleHomePageUrl(
246       GURL(pref_service->GetString(prefs::kHomePage)));
247
248   bool is_google_in_startpages = false;
249 #if !defined(OS_IOS)
250   // iOS does not have a notion of startpages.
251   SessionStartupPref session_startup_prefs =
252       StartupBrowserCreator::GetSessionStartupPref(
253           *CommandLine::ForCurrentProcess(), profile);
254   if (session_startup_prefs.type == SessionStartupPref::URLS) {
255     is_google_in_startpages =
256         std::count_if(session_startup_prefs.urls.begin(),
257                       session_startup_prefs.urls.end(),
258                       google_util::IsGoogleHomePageUrl) > 0;
259   }
260 #endif
261
262   if (!InitRlzDelayed(first_run, send_ping_immediately, delay,
263                       is_google_default_search, is_google_homepage,
264                       is_google_in_startpages)) {
265     return false;
266   }
267
268 #if !defined(OS_IOS)
269   // Prime the RLZ cache for the home page access point so that its avaiable
270   // for the startup page if needed (i.e., when the startup page is set to
271   // the home page).
272   GetAccessPointRlz(ChromeHomePage(), NULL);
273 #endif  // !defined(OS_IOS)
274
275   return true;
276 }
277
278 bool RLZTracker::Init(bool first_run,
279                       bool send_ping_immediately,
280                       base::TimeDelta delay,
281                       bool is_google_default_search,
282                       bool is_google_homepage,
283                       bool is_google_in_startpages) {
284   first_run_ = first_run;
285   is_google_default_search_ = is_google_default_search;
286   is_google_homepage_ = is_google_homepage;
287   is_google_in_startpages_ = is_google_in_startpages;
288   send_ping_immediately_ = send_ping_immediately;
289
290   // Enable zero delays for testing.
291   if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType))
292     EnableZeroDelayForTesting();
293
294   delay = std::min(kMaxInitDelay, std::max(min_init_delay_, delay));
295
296   if (google_brand::GetBrand(&brand_) && !IsBrandOrganic(brand_)) {
297     // Register for notifications from the omnibox so that we can record when
298     // the user performs a first search.
299     registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
300                    content::NotificationService::AllSources());
301
302 #if !defined(OS_IOS)
303     // Register for notifications from navigations, to see if the user has used
304     // the home page.
305     registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
306                    content::NotificationService::AllSources());
307 #endif  // !defined(OS_IOS)
308   }
309   google_brand::GetReactivationBrand(&reactivation_brand_);
310
311   net::URLRequestContextGetter* context_getter =
312       g_browser_process->system_request_context();
313
314   // Could be NULL; don't run if so.  RLZ will try again next restart.
315   if (context_getter) {
316     rlz_lib::SetURLRequestContext(context_getter);
317     ScheduleDelayedInit(delay);
318   }
319
320   return true;
321 }
322
323 void RLZTracker::ScheduleDelayedInit(base::TimeDelta delay) {
324   // The RLZTracker is a singleton object that outlives any runnable tasks
325   // that will be queued up.
326   BrowserThread::GetBlockingPool()->PostDelayedSequencedWorkerTask(
327       worker_pool_token_,
328       FROM_HERE,
329       base::Bind(&RLZTracker::DelayedInit, base::Unretained(this)),
330       delay);
331 }
332
333 void RLZTracker::DelayedInit() {
334   bool schedule_ping = false;
335
336   // For organic brandcodes do not use rlz at all. Empty brandcode usually
337   // means a chromium install. This is ok.
338   if (!IsBrandOrganic(brand_)) {
339     RecordProductEvents(first_run_, is_google_default_search_,
340                         is_google_homepage_, is_google_in_startpages_,
341                         already_ran_, omnibox_used_, homepage_used_,
342                         app_list_used_);
343     schedule_ping = true;
344   }
345
346   // If chrome has been reactivated, record the events for this brand
347   // as well.
348   if (!IsBrandOrganic(reactivation_brand_)) {
349     rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
350     RecordProductEvents(first_run_, is_google_default_search_,
351                         is_google_homepage_, is_google_in_startpages_,
352                         already_ran_, omnibox_used_, homepage_used_,
353                         app_list_used_);
354     schedule_ping = true;
355   }
356
357   already_ran_ = true;
358
359   if (schedule_ping)
360     ScheduleFinancialPing();
361 }
362
363 void RLZTracker::ScheduleFinancialPing() {
364   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
365       worker_pool_token_,
366       FROM_HERE,
367       base::Bind(&RLZTracker::PingNowImpl, base::Unretained(this)),
368       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
369 }
370
371 void RLZTracker::PingNowImpl() {
372   TRACE_EVENT0("RLZ", "RLZTracker::PingNowImpl");
373   base::string16 lang;
374   GoogleUpdateSettings::GetLanguage(&lang);
375   if (lang.empty())
376     lang = base::ASCIIToUTF16("en");
377   base::string16 referral;
378   GoogleUpdateSettings::GetReferral(&referral);
379
380   if (!IsBrandOrganic(brand_) && SendFinancialPing(brand_, lang, referral)) {
381     GoogleUpdateSettings::ClearReferral();
382
383     {
384       base::AutoLock lock(cache_lock_);
385       rlz_cache_.clear();
386     }
387
388     // Prime the RLZ cache for the access points we are interested in.
389     GetAccessPointRlz(RLZTracker::ChromeOmnibox(), NULL);
390 #if !defined(OS_IOS)
391     GetAccessPointRlz(RLZTracker::ChromeHomePage(), NULL);
392     GetAccessPointRlz(RLZTracker::ChromeAppList(), NULL);
393 #endif  // !defined(OS_IOS)
394   }
395
396   if (!IsBrandOrganic(reactivation_brand_)) {
397     rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
398     SendFinancialPing(reactivation_brand_, lang, referral);
399   }
400 }
401
402 bool RLZTracker::SendFinancialPing(const std::string& brand,
403                                    const base::string16& lang,
404                                    const base::string16& referral) {
405   return ::SendFinancialPing(brand, lang, referral);
406 }
407
408 void RLZTracker::Observe(int type,
409                          const content::NotificationSource& source,
410                          const content::NotificationDetails& details) {
411   switch (type) {
412     case chrome::NOTIFICATION_OMNIBOX_OPENED_URL:
413       // In M-36, we made NOTIFICATION_OMNIBOX_OPENED_URL fire more often than
414       // it did previously.  The RLZ folks want RLZ's "first search" detection
415       // to remain as unaffected as possible by this change.  This test is
416       // there to keep the old behavior.
417       if (!content::Details<OmniboxLog>(details).ptr()->is_popup_open)
418         break;
419       RecordFirstSearch(ChromeOmnibox());
420       registrar_.Remove(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
421                         content::NotificationService::AllSources());
422       break;
423 #if !defined(OS_IOS)
424     case content::NOTIFICATION_NAV_ENTRY_PENDING: {
425       const NavigationEntry* entry =
426           content::Details<content::NavigationEntry>(details).ptr();
427       if (entry != NULL &&
428           ((entry->GetTransitionType() &
429             ui::PAGE_TRANSITION_HOME_PAGE) != 0)) {
430         RecordFirstSearch(ChromeHomePage());
431         registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
432                           content::NotificationService::AllSources());
433       }
434       break;
435     }
436 #endif  // !defined(OS_IOS)
437     default:
438       NOTREACHED();
439       break;
440   }
441 }
442
443 // static
444 bool RLZTracker::RecordProductEvent(rlz_lib::Product product,
445                                     rlz_lib::AccessPoint point,
446                                     rlz_lib::Event event_id) {
447   return GetInstance()->RecordProductEventImpl(product, point, event_id);
448 }
449
450 bool RLZTracker::RecordProductEventImpl(rlz_lib::Product product,
451                                         rlz_lib::AccessPoint point,
452                                         rlz_lib::Event event_id) {
453   // Make sure we don't access disk outside of the I/O thread.
454   // In such case we repost the task on the right thread and return error.
455   if (ScheduleRecordProductEvent(product, point, event_id))
456     return true;
457
458   bool ret = rlz_lib::RecordProductEvent(product, point, event_id);
459
460   // If chrome has been reactivated, record the event for this brand as well.
461   if (!reactivation_brand_.empty()) {
462     rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
463     ret &= rlz_lib::RecordProductEvent(product, point, event_id);
464   }
465
466   return ret;
467 }
468
469 bool RLZTracker::ScheduleRecordProductEvent(rlz_lib::Product product,
470                                             rlz_lib::AccessPoint point,
471                                             rlz_lib::Event event_id) {
472   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
473     return false;
474
475   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
476       worker_pool_token_,
477       FROM_HERE,
478       base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEvent),
479                  product, point, event_id),
480       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
481
482   return true;
483 }
484
485 void RLZTracker::RecordFirstSearch(rlz_lib::AccessPoint point) {
486   // Make sure we don't access disk outside of the I/O thread.
487   // In such case we repost the task on the right thread and return error.
488   if (ScheduleRecordFirstSearch(point))
489     return;
490
491   bool* record_used = GetAccessPointRecord(point);
492
493   // Try to record event now, else set the flag to try later when we
494   // attempt the ping.
495   if (!RecordProductEvent(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH))
496     *record_used = true;
497   else if (send_ping_immediately_ && point == ChromeOmnibox())
498     ScheduleDelayedInit(base::TimeDelta());
499 }
500
501 bool RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) {
502   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
503     return false;
504   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
505       worker_pool_token_,
506       FROM_HERE,
507       base::Bind(&RLZTracker::RecordFirstSearch,
508                  base::Unretained(this), point),
509       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
510   return true;
511 }
512
513 bool* RLZTracker::GetAccessPointRecord(rlz_lib::AccessPoint point) {
514   if (point == ChromeOmnibox())
515     return &omnibox_used_;
516 #if !defined(OS_IOS)
517   if (point == ChromeHomePage())
518     return &homepage_used_;
519   if (point == ChromeAppList())
520     return &app_list_used_;
521 #endif  // !defined(OS_IOS)
522   NOTREACHED();
523   return NULL;
524 }
525
526 // static
527 std::string RLZTracker::GetAccessPointHttpHeader(rlz_lib::AccessPoint point) {
528   TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointHttpHeader");
529   std::string extra_headers;
530   base::string16 rlz_string;
531   RLZTracker::GetAccessPointRlz(point, &rlz_string);
532   if (!rlz_string.empty()) {
533     net::HttpUtil::AppendHeaderIfMissing("X-Rlz-String",
534                                          base::UTF16ToUTF8(rlz_string),
535                                          &extra_headers);
536   }
537
538   return extra_headers;
539 }
540
541 // GetAccessPointRlz() caches RLZ strings for all access points. If we had
542 // a successful ping, then we update the cached value.
543 bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point,
544                                    base::string16* rlz) {
545   TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointRlz");
546   return GetInstance()->GetAccessPointRlzImpl(point, rlz);
547 }
548
549 // GetAccessPointRlz() caches RLZ strings for all access points. If we had
550 // a successful ping, then we update the cached value.
551 bool RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point,
552                                        base::string16* rlz) {
553   // If the RLZ string for the specified access point is already cached,
554   // simply return its value.
555   {
556     base::AutoLock lock(cache_lock_);
557     if (rlz_cache_.find(point) != rlz_cache_.end()) {
558       if (rlz)
559         *rlz = rlz_cache_[point];
560       return true;
561     }
562   }
563
564   // Make sure we don't access disk outside of the I/O thread.
565   // In such case we repost the task on the right thread and return error.
566   if (ScheduleGetAccessPointRlz(point))
567     return false;
568
569   char str_rlz[rlz_lib::kMaxRlzLength + 1];
570   if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength))
571     return false;
572
573   base::string16 rlz_local(base::ASCIIToUTF16(std::string(str_rlz)));
574   if (rlz)
575     *rlz = rlz_local;
576
577   base::AutoLock lock(cache_lock_);
578   rlz_cache_[point] = rlz_local;
579   return true;
580 }
581
582 bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) {
583   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
584     return false;
585
586   base::string16* not_used = NULL;
587   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
588       worker_pool_token_,
589       FROM_HERE,
590       base::Bind(base::IgnoreResult(&RLZTracker::GetAccessPointRlz), point,
591                  not_used),
592       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
593   return true;
594 }
595
596 #if defined(OS_CHROMEOS)
597 // static
598 void RLZTracker::ClearRlzState() {
599   GetInstance()->ClearRlzStateImpl();
600 }
601
602 void RLZTracker::ClearRlzStateImpl() {
603   if (ScheduleClearRlzState())
604     return;
605   rlz_lib::ClearAllProductEvents(rlz_lib::CHROME);
606 }
607
608 bool RLZTracker::ScheduleClearRlzState() {
609   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
610     return false;
611
612   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
613       worker_pool_token_,
614       FROM_HERE,
615       base::Bind(&RLZTracker::ClearRlzStateImpl,
616                  base::Unretained(this)),
617       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
618   return true;
619 }
620 #endif
621
622 // static
623 void RLZTracker::CleanupRlz() {
624   GetInstance()->rlz_cache_.clear();
625   GetInstance()->registrar_.RemoveAll();
626   rlz_lib::SetURLRequestContext(NULL);
627 }
628
629 // static
630 void RLZTracker::EnableZeroDelayForTesting() {
631   GetInstance()->min_init_delay_ = base::TimeDelta();
632 }
633
634 #if !defined(OS_IOS)
635 // static
636 void RLZTracker::RecordAppListSearch() {
637   GetInstance()->RecordFirstSearch(RLZTracker::ChromeAppList());
638 }
639 #endif