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(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(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 string16& lang,
    136                        const 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_MACOSX)
    164 // static
    165 const rlz_lib::AccessPoint RLZTracker::CHROME_OMNIBOX =
    166     rlz_lib::CHROME_MAC_OMNIBOX;
    167 // static
    168 const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE =
    169     rlz_lib::CHROME_MAC_HOME_PAGE;
    170 #elif defined(OS_CHROMEOS)
    171 // static
    172 const rlz_lib::AccessPoint RLZTracker::CHROME_OMNIBOX =
    173     rlz_lib::CHROMEOS_OMNIBOX;
    174 // static
    175 const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE =
    176     rlz_lib::CHROMEOS_HOME_PAGE;
    177 #endif
    178 
    179 RLZTracker* RLZTracker::tracker_ = NULL;
    180 
    181 // static
    182 RLZTracker* RLZTracker::GetInstance() {
    183   return tracker_ ? tracker_ : Singleton<RLZTracker>::get();
    184 }
    185 
    186 RLZTracker::RLZTracker()
    187     : first_run_(false),
    188       send_ping_immediately_(false),
    189       is_google_default_search_(false),
    190       is_google_homepage_(false),
    191       is_google_in_startpages_(false),
    192       worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()),
    193       already_ran_(false),
    194       omnibox_used_(false),
    195       homepage_used_(false),
    196       min_init_delay_(kMinInitDelay) {
    197 }
    198 
    199 RLZTracker::~RLZTracker() {
    200 }
    201 
    202 // static
    203 bool RLZTracker::InitRlzDelayed(bool first_run,
    204                                 bool send_ping_immediately,
    205                                 base::TimeDelta delay,
    206                                 bool is_google_default_search,
    207                                 bool is_google_homepage,
    208                                 bool is_google_in_startpages) {
    209   return GetInstance()->Init(first_run, send_ping_immediately, delay,
    210                              is_google_default_search, is_google_homepage,
    211                              is_google_in_startpages);
    212 }
    213 
    214 // static
    215 bool RLZTracker::InitRlzFromProfileDelayed(Profile* profile,
    216                                            bool first_run,
    217                                            bool send_ping_immediately,
    218                                            base::TimeDelta delay) {
    219   bool is_google_default_search = false;
    220   TemplateURLService* template_url_service =
    221       TemplateURLServiceFactory::GetForProfile(profile);
    222   if (template_url_service) {
    223     const TemplateURL* url_template =
    224         template_url_service->GetDefaultSearchProvider();
    225     is_google_default_search =
    226         url_template && url_template->url_ref().HasGoogleBaseURLs();
    227   }
    228 
    229   PrefService* pref_service = profile->GetPrefs();
    230   bool is_google_homepage = google_util::IsGoogleHomePageUrl(
    231       GURL(pref_service->GetString(prefs::kHomePage)));
    232 
    233   bool is_google_in_startpages = false;
    234   SessionStartupPref session_startup_prefs =
    235       StartupBrowserCreator::GetSessionStartupPref(
    236           *CommandLine::ForCurrentProcess(), profile);
    237   if (session_startup_prefs.type == SessionStartupPref::URLS) {
    238     is_google_in_startpages =
    239         std::count_if(session_startup_prefs.urls.begin(),
    240                       session_startup_prefs.urls.end(),
    241                       google_util::IsGoogleHomePageUrl) > 0;
    242   }
    243 
    244   if (!InitRlzDelayed(first_run, send_ping_immediately, delay,
    245                       is_google_default_search, is_google_homepage,
    246                       is_google_in_startpages)) {
    247     return false;
    248   }
    249 
    250   // Prime the RLZ cache for the home page access point so that its avaiable
    251   // for the startup page if needed (i.e., when the startup page is set to
    252   // the home page).
    253   GetAccessPointRlz(CHROME_HOME_PAGE, NULL);
    254 
    255   return true;
    256 }
    257 
    258 bool RLZTracker::Init(bool first_run,
    259                       bool send_ping_immediately,
    260                       base::TimeDelta delay,
    261                       bool is_google_default_search,
    262                       bool is_google_homepage,
    263                       bool is_google_in_startpages) {
    264   first_run_ = first_run;
    265   is_google_default_search_ = is_google_default_search;
    266   is_google_homepage_ = is_google_homepage;
    267   is_google_in_startpages_ = is_google_in_startpages;
    268   send_ping_immediately_ = send_ping_immediately;
    269 
    270   // Enable zero delays for testing.
    271   if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType))
    272     EnableZeroDelayForTesting();
    273 
    274   delay = std::min(kMaxInitDelay, std::max(min_init_delay_, delay));
    275 
    276   if (google_util::GetBrand(&brand_) && !IsBrandOrganic(brand_)) {
    277     // Register for notifications from the omnibox so that we can record when
    278     // the user performs a first search.
    279     registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
    280                    content::NotificationService::AllSources());
    281 
    282     // Register for notifications from navigations, to see if the user has used
    283     // the home page.
    284     registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
    285                    content::NotificationService::AllSources());
    286   }
    287   google_util::GetReactivationBrand(&reactivation_brand_);
    288 
    289   net::URLRequestContextGetter* context_getter =
    290       g_browser_process->system_request_context();
    291 
    292   // Could be NULL; don't run if so.  RLZ will try again next restart.
    293   if (context_getter) {
    294     rlz_lib::SetURLRequestContext(context_getter);
    295     ScheduleDelayedInit(delay);
    296   }
    297 
    298   return true;
    299 }
    300 
    301 void RLZTracker::ScheduleDelayedInit(base::TimeDelta delay) {
    302   // The RLZTracker is a singleton object that outlives any runnable tasks
    303   // that will be queued up.
    304   BrowserThread::GetBlockingPool()->PostDelayedSequencedWorkerTask(
    305       worker_pool_token_,
    306       FROM_HERE,
    307       base::Bind(&RLZTracker::DelayedInit, base::Unretained(this)),
    308       delay);
    309 }
    310 
    311 void RLZTracker::DelayedInit() {
    312   bool schedule_ping = false;
    313 
    314   // For organic brandcodes do not use rlz at all. Empty brandcode usually
    315   // means a chromium install. This is ok.
    316   if (!IsBrandOrganic(brand_)) {
    317     RecordProductEvents(first_run_, is_google_default_search_,
    318                         is_google_homepage_, is_google_in_startpages_,
    319                         already_ran_, omnibox_used_, homepage_used_);
    320     schedule_ping = true;
    321   }
    322 
    323   // If chrome has been reactivated, record the events for this brand
    324   // as well.
    325   if (!IsBrandOrganic(reactivation_brand_)) {
    326     rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
    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   already_ran_ = true;
    334 
    335   if (schedule_ping)
    336     ScheduleFinancialPing();
    337 }
    338 
    339 void RLZTracker::ScheduleFinancialPing() {
    340   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
    341       worker_pool_token_,
    342       FROM_HERE,
    343       base::Bind(&RLZTracker::PingNowImpl, base::Unretained(this)),
    344       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
    345 }
    346 
    347 void RLZTracker::PingNowImpl() {
    348   TRACE_EVENT0("RLZ", "RLZTracker::PingNowImpl");
    349   string16 lang;
    350   GoogleUpdateSettings::GetLanguage(&lang);
    351   if (lang.empty())
    352     lang = ASCIIToUTF16("en");
    353   string16 referral;
    354   GoogleUpdateSettings::GetReferral(&referral);
    355 
    356   if (!IsBrandOrganic(brand_) && SendFinancialPing(brand_, lang, referral)) {
    357     GoogleUpdateSettings::ClearReferral();
    358 
    359     {
    360       base::AutoLock lock(cache_lock_);
    361       rlz_cache_.clear();
    362     }
    363 
    364     // Prime the RLZ cache for the access points we are interested in.
    365     GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, NULL);
    366     GetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, NULL);
    367   }
    368 
    369   if (!IsBrandOrganic(reactivation_brand_)) {
    370     rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
    371     SendFinancialPing(reactivation_brand_, lang, referral);
    372   }
    373 }
    374 
    375 bool RLZTracker::SendFinancialPing(const std::string& brand,
    376                                    const string16& lang,
    377                                    const string16& referral) {
    378   return ::SendFinancialPing(brand, lang, referral);
    379 }
    380 
    381 void RLZTracker::Observe(int type,
    382                          const content::NotificationSource& source,
    383                          const content::NotificationDetails& details) {
    384   switch (type) {
    385     case chrome::NOTIFICATION_OMNIBOX_OPENED_URL:
    386       RecordFirstSearch(CHROME_OMNIBOX);
    387       registrar_.Remove(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
    388                         content::NotificationService::AllSources());
    389       break;
    390     case content::NOTIFICATION_NAV_ENTRY_PENDING: {
    391       const NavigationEntry* entry =
    392           content::Details<content::NavigationEntry>(details).ptr();
    393       if (entry != NULL &&
    394           ((entry->GetTransitionType() &
    395             content::PAGE_TRANSITION_HOME_PAGE) != 0)) {
    396         RecordFirstSearch(CHROME_HOME_PAGE);
    397         registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
    398                           content::NotificationService::AllSources());
    399       }
    400       break;
    401     }
    402     default:
    403       NOTREACHED();
    404       break;
    405   }
    406 }
    407 
    408 // static
    409 bool RLZTracker::RecordProductEvent(rlz_lib::Product product,
    410                                     rlz_lib::AccessPoint point,
    411                                     rlz_lib::Event event_id) {
    412   return GetInstance()->RecordProductEventImpl(product, point, event_id);
    413 }
    414 
    415 bool RLZTracker::RecordProductEventImpl(rlz_lib::Product product,
    416                                         rlz_lib::AccessPoint point,
    417                                         rlz_lib::Event event_id) {
    418   // Make sure we don't access disk outside of the I/O thread.
    419   // In such case we repost the task on the right thread and return error.
    420   if (ScheduleRecordProductEvent(product, point, event_id))
    421     return true;
    422 
    423   bool ret = rlz_lib::RecordProductEvent(product, point, event_id);
    424 
    425   // If chrome has been reactivated, record the event for this brand as well.
    426   if (!reactivation_brand_.empty()) {
    427     rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
    428     ret &= rlz_lib::RecordProductEvent(product, point, event_id);
    429   }
    430 
    431   return ret;
    432 }
    433 
    434 bool RLZTracker::ScheduleRecordProductEvent(rlz_lib::Product product,
    435                                             rlz_lib::AccessPoint point,
    436                                             rlz_lib::Event event_id) {
    437   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    438     return false;
    439 
    440   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
    441       worker_pool_token_,
    442       FROM_HERE,
    443       base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEvent),
    444                  product, point, event_id),
    445       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
    446 
    447   return true;
    448 }
    449 
    450 void RLZTracker::RecordFirstSearch(rlz_lib::AccessPoint point) {
    451   // Make sure we don't access disk outside of the I/O thread.
    452   // In such case we repost the task on the right thread and return error.
    453   if (ScheduleRecordFirstSearch(point))
    454     return;
    455 
    456   bool* record_used = point == CHROME_OMNIBOX ?
    457       &omnibox_used_ : &homepage_used_;
    458 
    459   // Try to record event now, else set the flag to try later when we
    460   // attempt the ping.
    461   if (!RecordProductEvent(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH))
    462     *record_used = true;
    463   else if (send_ping_immediately_ && point == CHROME_OMNIBOX)
    464     ScheduleDelayedInit(base::TimeDelta());
    465 }
    466 
    467 bool RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) {
    468   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    469     return false;
    470   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
    471       worker_pool_token_,
    472       FROM_HERE,
    473       base::Bind(&RLZTracker::RecordFirstSearch,
    474                  base::Unretained(this), point),
    475       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
    476   return true;
    477 }
    478 
    479 // static
    480 std::string RLZTracker::GetAccessPointHttpHeader(rlz_lib::AccessPoint point) {
    481   TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointHttpHeader");
    482   std::string extra_headers;
    483   string16 rlz_string;
    484   RLZTracker::GetAccessPointRlz(point, &rlz_string);
    485   if (!rlz_string.empty()) {
    486     net::HttpUtil::AppendHeaderIfMissing("X-Rlz-String",
    487                                          UTF16ToUTF8(rlz_string),
    488                                          &extra_headers);
    489   }
    490 
    491   return extra_headers;
    492 }
    493 
    494 // GetAccessPointRlz() caches RLZ strings for all access points. If we had
    495 // a successful ping, then we update the cached value.
    496 bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point,
    497                                    string16* rlz) {
    498   TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointRlz");
    499   return GetInstance()->GetAccessPointRlzImpl(point, rlz);
    500 }
    501 
    502 // GetAccessPointRlz() caches RLZ strings for all access points. If we had
    503 // a successful ping, then we update the cached value.
    504 bool RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point,
    505                                        string16* rlz) {
    506   // If the RLZ string for the specified access point is already cached,
    507   // simply return its value.
    508   {
    509     base::AutoLock lock(cache_lock_);
    510     if (rlz_cache_.find(point) != rlz_cache_.end()) {
    511       if (rlz)
    512         *rlz = rlz_cache_[point];
    513       return true;
    514     }
    515   }
    516 
    517   // Make sure we don't access disk outside of the I/O thread.
    518   // In such case we repost the task on the right thread and return error.
    519   if (ScheduleGetAccessPointRlz(point))
    520     return false;
    521 
    522   char str_rlz[rlz_lib::kMaxRlzLength + 1];
    523   if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength))
    524     return false;
    525 
    526   string16 rlz_local(ASCIIToUTF16(std::string(str_rlz)));
    527   if (rlz)
    528     *rlz = rlz_local;
    529 
    530   base::AutoLock lock(cache_lock_);
    531   rlz_cache_[point] = rlz_local;
    532   return true;
    533 }
    534 
    535 bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) {
    536   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    537     return false;
    538 
    539   string16* not_used = NULL;
    540   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
    541       worker_pool_token_,
    542       FROM_HERE,
    543       base::Bind(base::IgnoreResult(&RLZTracker::GetAccessPointRlz), point,
    544                  not_used),
    545       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
    546   return true;
    547 }
    548 
    549 #if defined(OS_CHROMEOS)
    550 // static
    551 void RLZTracker::ClearRlzState() {
    552   GetInstance()->ClearRlzStateImpl();
    553 }
    554 
    555 void RLZTracker::ClearRlzStateImpl() {
    556   if (ScheduleClearRlzState())
    557     return;
    558   rlz_lib::ClearAllProductEvents(rlz_lib::CHROME);
    559 }
    560 
    561 bool RLZTracker::ScheduleClearRlzState() {
    562   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    563     return false;
    564 
    565   BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
    566       worker_pool_token_,
    567       FROM_HERE,
    568       base::Bind(&RLZTracker::ClearRlzStateImpl,
    569                  base::Unretained(this)),
    570       base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
    571   return true;
    572 }
    573 #endif
    574 
    575 // static
    576 void RLZTracker::CleanupRlz() {
    577   GetInstance()->rlz_cache_.clear();
    578   GetInstance()->registrar_.RemoveAll();
    579   rlz_lib::SetURLRequestContext(NULL);
    580 }
    581 
    582 // static
    583 void RLZTracker::EnableZeroDelayForTesting() {
    584   GetInstance()->min_init_delay_ = base::TimeDelta();
    585 }
    586