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 {
GetLanguage(base::string16 * language)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.
GetReferral(base::string16 * referral)47 static bool GetReferral(base::string16* referral) {
48 return true;
49 }
ClearReferral()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
IsBrandOrganic(const std::string & brand)66 bool IsBrandOrganic(const std::string& brand) {
67 return brand.empty() || google_util::IsOrganic(brand);
68 }
69
RecordProductEvents(bool first_run,bool is_google_default_search,bool is_google_homepage,bool is_google_in_startpages,bool already_ran,bool omnibox_used,bool homepage_used)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
SendFinancialPing(const std::string & brand,const base::string16 & lang,const base::string16 & referral)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
GetInstance()189 RLZTracker* RLZTracker::GetInstance() {
190 return tracker_ ? tracker_ : Singleton<RLZTracker>::get();
191 }
192
RLZTracker()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
~RLZTracker()206 RLZTracker::~RLZTracker() {
207 }
208
209 // static
InitRlzDelayed(bool first_run,bool send_ping_immediately,base::TimeDelta delay,bool is_google_default_search,bool is_google_homepage,bool is_google_in_startpages)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
InitRlzFromProfileDelayed(Profile * profile,bool first_run,bool send_ping_immediately,base::TimeDelta delay)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
Init(bool first_run,bool send_ping_immediately,base::TimeDelta delay,bool is_google_default_search,bool is_google_homepage,bool is_google_in_startpages)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
ScheduleDelayedInit(base::TimeDelta delay)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
DelayedInit()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
ScheduleFinancialPing()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
PingNowImpl()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
SendFinancialPing(const std::string & brand,const base::string16 & lang,const base::string16 & referral)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
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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
RecordProductEvent(rlz_lib::Product product,rlz_lib::AccessPoint point,rlz_lib::Event event_id)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
RecordProductEventImpl(rlz_lib::Product product,rlz_lib::AccessPoint point,rlz_lib::Event event_id)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
ScheduleRecordProductEvent(rlz_lib::Product product,rlz_lib::AccessPoint point,rlz_lib::Event event_id)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
RecordFirstSearch(rlz_lib::AccessPoint point)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
ScheduleRecordFirstSearch(rlz_lib::AccessPoint point)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
GetAccessPointHttpHeader(rlz_lib::AccessPoint point)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.
GetAccessPointRlz(rlz_lib::AccessPoint point,base::string16 * rlz)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.
GetAccessPointRlzImpl(rlz_lib::AccessPoint point,base::string16 * rlz)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
ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point)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
ClearRlzState()561 void RLZTracker::ClearRlzState() {
562 GetInstance()->ClearRlzStateImpl();
563 }
564
ClearRlzStateImpl()565 void RLZTracker::ClearRlzStateImpl() {
566 if (ScheduleClearRlzState())
567 return;
568 rlz_lib::ClearAllProductEvents(rlz_lib::CHROME);
569 }
570
ScheduleClearRlzState()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
CleanupRlz()586 void RLZTracker::CleanupRlz() {
587 GetInstance()->rlz_cache_.clear();
588 GetInstance()->registrar_.RemoveAll();
589 rlz_lib::SetURLRequestContext(NULL);
590 }
591
592 // static
EnableZeroDelayForTesting()593 void RLZTracker::EnableZeroDelayForTesting() {
594 GetInstance()->min_init_delay_ = base::TimeDelta();
595 }
596