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