This source file includes following definitions.
- GetLanguage
- GetReferral
- ClearReferral
- IsBrandOrganic
- RecordProductEvents
- SendFinancialPing
- GetInstance
- min_init_delay_
- InitRlzDelayed
- InitRlzFromProfileDelayed
- Init
- ScheduleDelayedInit
- DelayedInit
- ScheduleFinancialPing
- PingNowImpl
- SendFinancialPing
- Observe
- RecordProductEvent
- RecordProductEventImpl
- ScheduleRecordProductEvent
- RecordFirstSearch
- ScheduleRecordFirstSearch
- GetAccessPointRecord
- GetAccessPointHttpHeader
- GetAccessPointRlz
- GetAccessPointRlzImpl
- ScheduleGetAccessPointRlz
- ClearRlzState
- ClearRlzStateImpl
- ScheduleClearRlzState
- CleanupRlz
- EnableZeroDelayForTesting
- RecordAppListSearch
#include "chrome/browser/rlz/rlz.h"
#include <algorithm>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/startup/startup_browser_creator.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "net/http/http_util.h"
#if defined(OS_WIN)
#include "chrome/installer/util/google_update_settings.h"
#else
namespace GoogleUpdateSettings {
static bool GetLanguage(base::string16* language) {
  
  NOTIMPLEMENTED();
  return false;
}
static bool GetReferral(base::string16* referral) {
  return true;
}
static bool ClearReferral() {
  return true;
}
}  
#endif
using content::BrowserThread;
using content::NavigationEntry;
namespace {
const base::TimeDelta kMaxInitDelay = base::TimeDelta::FromSeconds(200);
const base::TimeDelta kMinInitDelay = base::TimeDelta::FromSeconds(20);
bool IsBrandOrganic(const std::string& brand) {
  return brand.empty() || google_util::IsOrganic(brand);
}
void 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,
                         bool app_list_used) {
  TRACE_EVENT0("RLZ", "RecordProductEvents");
  
  
  rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                              RLZTracker::CHROME_OMNIBOX,
                              rlz_lib::INSTALL);
  rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                              RLZTracker::CHROME_HOME_PAGE,
                              rlz_lib::INSTALL);
#if !defined(OS_IOS)
  rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                              RLZTracker::CHROME_APP_LIST,
                              rlz_lib::INSTALL);
#endif
  if (!already_ran) {
    
    
    char omnibox_rlz[rlz_lib::kMaxRlzLength + 1];
    if (!rlz_lib::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, omnibox_rlz,
                                    rlz_lib::kMaxRlzLength)) {
      omnibox_rlz[0] = 0;
    }
    
    if ((first_run || omnibox_rlz[0] == 0) && is_google_default_search) {
      rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                                  RLZTracker::CHROME_OMNIBOX,
                                  rlz_lib::SET_TO_GOOGLE);
    }
    char homepage_rlz[rlz_lib::kMaxRlzLength + 1];
    if (!rlz_lib::GetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, homepage_rlz,
                                    rlz_lib::kMaxRlzLength)) {
      homepage_rlz[0] = 0;
    }
    if ((first_run || homepage_rlz[0] == 0) &&
        (is_google_homepage || is_google_in_startpages)) {
      rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                                  RLZTracker::CHROME_HOME_PAGE,
                                  rlz_lib::SET_TO_GOOGLE);
    }
#if !defined(OS_IOS)
    char app_list_rlz[rlz_lib::kMaxRlzLength + 1];
    if (!rlz_lib::GetAccessPointRlz(RLZTracker::CHROME_APP_LIST, app_list_rlz,
                                    rlz_lib::kMaxRlzLength)) {
      app_list_rlz[0] = 0;
    }
    
    if ((first_run || app_list_rlz[0] == 0) && is_google_default_search) {
      rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                                  RLZTracker::CHROME_APP_LIST,
                                  rlz_lib::SET_TO_GOOGLE);
    }
#endif
  }
  
  
  if (omnibox_used) {
    rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                                RLZTracker::CHROME_OMNIBOX,
                                rlz_lib::FIRST_SEARCH);
  }
  
  
  if (homepage_used || is_google_in_startpages) {
    rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                                RLZTracker::CHROME_HOME_PAGE,
                                rlz_lib::FIRST_SEARCH);
  }
#if !defined(OS_IOS)
  
  
  if (app_list_used) {
    rlz_lib::RecordProductEvent(rlz_lib::CHROME,
                                RLZTracker::CHROME_APP_LIST,
                                rlz_lib::FIRST_SEARCH);
  }
#endif
}
bool SendFinancialPing(const std::string& brand,
                       const base::string16& lang,
                       const base::string16& referral) {
  rlz_lib::AccessPoint points[] = {RLZTracker::CHROME_OMNIBOX,
                                   RLZTracker::CHROME_HOME_PAGE,
#if !defined(OS_IOS)
                                   RLZTracker::CHROME_APP_LIST,
#endif
                                   rlz_lib::NO_ACCESS_POINT};
  std::string lang_ascii(base::UTF16ToASCII(lang));
  std::string referral_ascii(base::UTF16ToASCII(referral));
  std::string product_signature;
#if defined(OS_CHROMEOS)
  product_signature = "chromeos";
#else
  product_signature = "chrome";
#endif
  return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points,
                                    product_signature.c_str(),
                                    brand.c_str(), referral_ascii.c_str(),
                                    lang_ascii.c_str(), false, true);
}
}  
#if defined(OS_WIN)
const rlz_lib::AccessPoint RLZTracker::CHROME_OMNIBOX =
    rlz_lib::CHROME_OMNIBOX;
const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE =
    rlz_lib::CHROME_HOME_PAGE;
const rlz_lib::AccessPoint RLZTracker::CHROME_APP_LIST =
    rlz_lib::CHROME_APP_LIST;
#elif defined(OS_IOS)
const rlz_lib::AccessPoint RLZTracker::CHROME_OMNIBOX =
    rlz_lib::CHROME_IOS_OMNIBOX;
const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE =
    rlz_lib::CHROME_IOS_HOME_PAGE;
#elif defined(OS_MACOSX)
const rlz_lib::AccessPoint RLZTracker::CHROME_OMNIBOX =
    rlz_lib::CHROME_MAC_OMNIBOX;
const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE =
    rlz_lib::CHROME_MAC_HOME_PAGE;
const rlz_lib::AccessPoint RLZTracker::CHROME_APP_LIST =
    rlz_lib::CHROME_MAC_APP_LIST;
#elif defined(OS_CHROMEOS)
const rlz_lib::AccessPoint RLZTracker::CHROME_OMNIBOX =
    rlz_lib::CHROMEOS_OMNIBOX;
const rlz_lib::AccessPoint RLZTracker::CHROME_HOME_PAGE =
    rlz_lib::CHROMEOS_HOME_PAGE;
const rlz_lib::AccessPoint RLZTracker::CHROME_APP_LIST =
    rlz_lib::CHROMEOS_APP_LIST;
#endif
RLZTracker* RLZTracker::tracker_ = NULL;
RLZTracker* RLZTracker::GetInstance() {
  return tracker_ ? tracker_ : Singleton<RLZTracker>::get();
}
RLZTracker::RLZTracker()
    : first_run_(false),
      send_ping_immediately_(false),
      is_google_default_search_(false),
      is_google_homepage_(false),
      is_google_in_startpages_(false),
      worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()),
      already_ran_(false),
      omnibox_used_(false),
      homepage_used_(false),
      app_list_used_(false),
      min_init_delay_(kMinInitDelay) {
}
RLZTracker::~RLZTracker() {
}
bool RLZTracker::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) {
  return GetInstance()->Init(first_run, send_ping_immediately, delay,
                             is_google_default_search, is_google_homepage,
                             is_google_in_startpages);
}
bool RLZTracker::InitRlzFromProfileDelayed(Profile* profile,
                                           bool first_run,
                                           bool send_ping_immediately,
                                           base::TimeDelta delay) {
  bool is_google_default_search = false;
  TemplateURLService* template_url_service =
      TemplateURLServiceFactory::GetForProfile(profile);
  if (template_url_service) {
    const TemplateURL* url_template =
        template_url_service->GetDefaultSearchProvider();
    is_google_default_search =
        url_template && url_template->url_ref().HasGoogleBaseURLs();
  }
  PrefService* pref_service = profile->GetPrefs();
  bool is_google_homepage = google_util::IsGoogleHomePageUrl(
      GURL(pref_service->GetString(prefs::kHomePage)));
  bool is_google_in_startpages = false;
#if !defined(OS_IOS)
  
  SessionStartupPref session_startup_prefs =
      StartupBrowserCreator::GetSessionStartupPref(
          *CommandLine::ForCurrentProcess(), profile);
  if (session_startup_prefs.type == SessionStartupPref::URLS) {
    is_google_in_startpages =
        std::count_if(session_startup_prefs.urls.begin(),
                      session_startup_prefs.urls.end(),
                      google_util::IsGoogleHomePageUrl) > 0;
  }
#endif
  if (!InitRlzDelayed(first_run, send_ping_immediately, delay,
                      is_google_default_search, is_google_homepage,
                      is_google_in_startpages)) {
    return false;
  }
  
  
  
  GetAccessPointRlz(CHROME_HOME_PAGE, NULL);
  return true;
}
bool RLZTracker::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) {
  first_run_ = first_run;
  is_google_default_search_ = is_google_default_search;
  is_google_homepage_ = is_google_homepage;
  is_google_in_startpages_ = is_google_in_startpages;
  send_ping_immediately_ = send_ping_immediately;
  
  if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType))
    EnableZeroDelayForTesting();
  delay = std::min(kMaxInitDelay, std::max(min_init_delay_, delay));
  if (google_util::GetBrand(&brand_) && !IsBrandOrganic(brand_)) {
    
    
    registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
                   content::NotificationService::AllSources());
    
    
    registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
                   content::NotificationService::AllSources());
  }
  google_util::GetReactivationBrand(&reactivation_brand_);
  net::URLRequestContextGetter* context_getter =
      g_browser_process->system_request_context();
  
  if (context_getter) {
    rlz_lib::SetURLRequestContext(context_getter);
    ScheduleDelayedInit(delay);
  }
  return true;
}
void RLZTracker::ScheduleDelayedInit(base::TimeDelta delay) {
  
  
  BrowserThread::GetBlockingPool()->PostDelayedSequencedWorkerTask(
      worker_pool_token_,
      FROM_HERE,
      base::Bind(&RLZTracker::DelayedInit, base::Unretained(this)),
      delay);
}
void RLZTracker::DelayedInit() {
  bool schedule_ping = false;
  
  
  if (!IsBrandOrganic(brand_)) {
    RecordProductEvents(first_run_, is_google_default_search_,
                        is_google_homepage_, is_google_in_startpages_,
                        already_ran_, omnibox_used_, homepage_used_,
                        app_list_used_);
    schedule_ping = true;
  }
  
  
  if (!IsBrandOrganic(reactivation_brand_)) {
    rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
    RecordProductEvents(first_run_, is_google_default_search_,
                        is_google_homepage_, is_google_in_startpages_,
                        already_ran_, omnibox_used_, homepage_used_,
                        app_list_used_);
    schedule_ping = true;
  }
  already_ran_ = true;
  if (schedule_ping)
    ScheduleFinancialPing();
}
void RLZTracker::ScheduleFinancialPing() {
  BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
      worker_pool_token_,
      FROM_HERE,
      base::Bind(&RLZTracker::PingNowImpl, base::Unretained(this)),
      base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
}
void RLZTracker::PingNowImpl() {
  TRACE_EVENT0("RLZ", "RLZTracker::PingNowImpl");
  base::string16 lang;
  GoogleUpdateSettings::GetLanguage(&lang);
  if (lang.empty())
    lang = base::ASCIIToUTF16("en");
  base::string16 referral;
  GoogleUpdateSettings::GetReferral(&referral);
  if (!IsBrandOrganic(brand_) && SendFinancialPing(brand_, lang, referral)) {
    GoogleUpdateSettings::ClearReferral();
    {
      base::AutoLock lock(cache_lock_);
      rlz_cache_.clear();
    }
    
    GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, NULL);
    GetAccessPointRlz(RLZTracker::CHROME_HOME_PAGE, NULL);
#if !defined(OS_IOS)
    GetAccessPointRlz(RLZTracker::CHROME_APP_LIST, NULL);
#endif
  }
  if (!IsBrandOrganic(reactivation_brand_)) {
    rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
    SendFinancialPing(reactivation_brand_, lang, referral);
  }
}
bool RLZTracker::SendFinancialPing(const std::string& brand,
                                   const base::string16& lang,
                                   const base::string16& referral) {
  return ::SendFinancialPing(brand, lang, referral);
}
void RLZTracker::Observe(int type,
                         const content::NotificationSource& source,
                         const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_OMNIBOX_OPENED_URL:
      RecordFirstSearch(CHROME_OMNIBOX);
      registrar_.Remove(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
                        content::NotificationService::AllSources());
      break;
    case content::NOTIFICATION_NAV_ENTRY_PENDING: {
      const NavigationEntry* entry =
          content::Details<content::NavigationEntry>(details).ptr();
      if (entry != NULL &&
          ((entry->GetTransitionType() &
            content::PAGE_TRANSITION_HOME_PAGE) != 0)) {
        RecordFirstSearch(CHROME_HOME_PAGE);
        registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
                          content::NotificationService::AllSources());
      }
      break;
    }
    default:
      NOTREACHED();
      break;
  }
}
bool RLZTracker::RecordProductEvent(rlz_lib::Product product,
                                    rlz_lib::AccessPoint point,
                                    rlz_lib::Event event_id) {
  return GetInstance()->RecordProductEventImpl(product, point, event_id);
}
bool RLZTracker::RecordProductEventImpl(rlz_lib::Product product,
                                        rlz_lib::AccessPoint point,
                                        rlz_lib::Event event_id) {
  
  
  if (ScheduleRecordProductEvent(product, point, event_id))
    return true;
  bool ret = rlz_lib::RecordProductEvent(product, point, event_id);
  
  if (!reactivation_brand_.empty()) {
    rlz_lib::SupplementaryBranding branding(reactivation_brand_.c_str());
    ret &= rlz_lib::RecordProductEvent(product, point, event_id);
  }
  return ret;
}
bool RLZTracker::ScheduleRecordProductEvent(rlz_lib::Product product,
                                            rlz_lib::AccessPoint point,
                                            rlz_lib::Event event_id) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    return false;
  BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
      worker_pool_token_,
      FROM_HERE,
      base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEvent),
                 product, point, event_id),
      base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
  return true;
}
void RLZTracker::RecordFirstSearch(rlz_lib::AccessPoint point) {
  
  
  if (ScheduleRecordFirstSearch(point))
    return;
  bool* record_used = GetAccessPointRecord(point);
  
  
  if (!RecordProductEvent(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH))
    *record_used = true;
  else if (send_ping_immediately_ && point == CHROME_OMNIBOX)
    ScheduleDelayedInit(base::TimeDelta());
}
bool RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    return false;
  BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
      worker_pool_token_,
      FROM_HERE,
      base::Bind(&RLZTracker::RecordFirstSearch,
                 base::Unretained(this), point),
      base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
  return true;
}
bool* RLZTracker::GetAccessPointRecord(rlz_lib::AccessPoint point) {
  if (point == CHROME_OMNIBOX)
    return &omnibox_used_;
  if (point == CHROME_HOME_PAGE)
    return &homepage_used_;
#if !defined(OS_IOS)
  if (point == CHROME_APP_LIST)
    return &app_list_used_;
#endif
  NOTREACHED();
  return NULL;
}
std::string RLZTracker::GetAccessPointHttpHeader(rlz_lib::AccessPoint point) {
  TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointHttpHeader");
  std::string extra_headers;
  base::string16 rlz_string;
  RLZTracker::GetAccessPointRlz(point, &rlz_string);
  if (!rlz_string.empty()) {
    net::HttpUtil::AppendHeaderIfMissing("X-Rlz-String",
                                         base::UTF16ToUTF8(rlz_string),
                                         &extra_headers);
  }
  return extra_headers;
}
bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point,
                                   base::string16* rlz) {
  TRACE_EVENT0("RLZ", "RLZTracker::GetAccessPointRlz");
  return GetInstance()->GetAccessPointRlzImpl(point, rlz);
}
bool RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point,
                                       base::string16* rlz) {
  
  
  {
    base::AutoLock lock(cache_lock_);
    if (rlz_cache_.find(point) != rlz_cache_.end()) {
      if (rlz)
        *rlz = rlz_cache_[point];
      return true;
    }
  }
  
  
  if (ScheduleGetAccessPointRlz(point))
    return false;
  char str_rlz[rlz_lib::kMaxRlzLength + 1];
  if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength))
    return false;
  base::string16 rlz_local(base::ASCIIToUTF16(std::string(str_rlz)));
  if (rlz)
    *rlz = rlz_local;
  base::AutoLock lock(cache_lock_);
  rlz_cache_[point] = rlz_local;
  return true;
}
bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    return false;
  base::string16* not_used = NULL;
  BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
      worker_pool_token_,
      FROM_HERE,
      base::Bind(base::IgnoreResult(&RLZTracker::GetAccessPointRlz), point,
                 not_used),
      base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
  return true;
}
#if defined(OS_CHROMEOS)
void RLZTracker::ClearRlzState() {
  GetInstance()->ClearRlzStateImpl();
}
void RLZTracker::ClearRlzStateImpl() {
  if (ScheduleClearRlzState())
    return;
  rlz_lib::ClearAllProductEvents(rlz_lib::CHROME);
}
bool RLZTracker::ScheduleClearRlzState() {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    return false;
  BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
      worker_pool_token_,
      FROM_HERE,
      base::Bind(&RLZTracker::ClearRlzStateImpl,
                 base::Unretained(this)),
      base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
  return true;
}
#endif
void RLZTracker::CleanupRlz() {
  GetInstance()->rlz_cache_.clear();
  GetInstance()->registrar_.RemoveAll();
  rlz_lib::SetURLRequestContext(NULL);
}
void RLZTracker::EnableZeroDelayForTesting() {
  GetInstance()->min_init_delay_ = base::TimeDelta();
}
#if !defined(OS_IOS)
void RLZTracker::RecordAppListSearch() {
  GetInstance()->RecordFirstSearch(RLZTracker::CHROME_APP_LIST);
}
#endif