172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This code glues the RLZ library DLL with Chrome. It allows Chrome to work
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// with or without the DLL being present. If the DLL is not present the
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// functions do nothing and just return false.
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/rlz/rlz.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <process.h>
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <windows.h>
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/synchronization/lock.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h"
223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
233f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h"
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
2621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
2721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h"
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/search_engines/template_url.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url_model.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/env_vars.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/google_update_settings.h"
33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_registrar.h"
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The maximum length of an access points RLZ in wide chars.
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst DWORD kMaxRlzLength = 64;
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochenum {
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ACCESS_VALUES_STALE,      // Possibly new values available.
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ACCESS_VALUES_FRESH       // The cached values are current.
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Tracks if we have tried and succeeded sending the ping. This helps us
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// decide if we need to refresh the some cached strings.
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvolatile int access_values_state = ACCESS_VALUES_STALE;
5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbase::Lock rlz_lock;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SendFinancialPing(const std::wstring& brand, const std::wstring& lang,
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const std::wstring& referral, bool exclude_id) {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX,
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   rlz_lib::CHROME_HOME_PAGE,
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   rlz_lib::NO_ACCESS_POINT};
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string brand_ascii(WideToASCII(brand));
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string lang_ascii(WideToASCII(lang));
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string referral_ascii(WideToASCII(referral));
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome",
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    brand_ascii.c_str(), referral_ascii.c_str(),
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    lang_ascii.c_str(), exclude_id, NULL, true);
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class leverages the AutocompleteEditModel notification to know when
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the user first interacted with the omnibox and set a global accordingly.
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass OmniBoxUsageObserver : public NotificationObserver {
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  OmniBoxUsageObserver(bool first_run, bool send_ping_immediately)
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : first_run_(first_run),
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      send_ping_immediately_(send_ping_immediately) {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Add(this, NotificationType::OMNIBOX_OPENED_URL,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   NotificationService::AllSources());
75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // If instant is enabled we'll start searching as soon as the user starts
76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // typing in the omnibox (which triggers INSTANT_CONTROLLER_UPDATED).
77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    registrar_.Add(this, NotificationType::INSTANT_CONTROLLER_UPDATED,
78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                   NotificationService::AllSources());
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    omnibox_used_ = false;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(!instance_);
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    instance_ = this;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Observe(NotificationType type,
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const NotificationSource& source,
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       const NotificationDetails& details);
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static bool used() {
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return omnibox_used_;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Deletes the single instance of OmniBoxUsageObserver.
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void DeleteInstance() {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete instance_;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Dtor is private so the object cannot be created on the stack.
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~OmniBoxUsageObserver() {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    instance_ = NULL;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static bool omnibox_used_;
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // There should only be one instance created at a time, and instance_ points
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to that instance.
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE: this is only non-null for the amount of time it is needed. Once the
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // instance_ is no longer needed (or Chrome is exiting), this is null.
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static OmniBoxUsageObserver* instance_;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationRegistrar registrar_;
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool first_run_;
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool send_ping_immediately_;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool OmniBoxUsageObserver::omnibox_used_ = false;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochOmniBoxUsageObserver* OmniBoxUsageObserver::instance_ = NULL;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This task is run in the file thread, so to not block it for a long time
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we use a throwaway thread to do the blocking url request.
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass DailyPingTask : public Task {
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual ~DailyPingTask() {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Run() {
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We use a transient thread because we have no guarantees about
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // how long the RLZ lib can block us.
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    _beginthread(PingNow, 0, NULL);
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Causes a ping to the server using WinInet.
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void _cdecl PingNow(void*) {
1344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // Needs to be evaluated. See http://crbug.com/62328.
1354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    base::ThreadRestrictions::ScopedAllowIO allow_io;
1364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring lang;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GoogleUpdateSettings::GetLanguage(&lang);
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (lang.empty())
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      lang = L"en";
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring brand;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GoogleUpdateSettings::GetBrand(&brand);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring referral;
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GoogleUpdateSettings::GetReferral(&referral);
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (SendFinancialPing(brand, lang, referral, is_organic(brand))) {
14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      base::AutoLock lock(rlz_lock);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      access_values_state = ACCESS_VALUES_STALE;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GoogleUpdateSettings::ClearReferral();
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Organic brands all start with GG, such as GGCM.
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static bool is_organic(const std::wstring& brand) {
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG");
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Performs late RLZ initialization and RLZ event recording for chrome.
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This task needs to run on the UI thread.
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass DelayedInitTask : public Task {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit DelayedInitTask(bool first_run)
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : first_run_(first_run) {
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual ~DelayedInitTask() {
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Run() {
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // For non-interactive tests we don't do the rest of the initialization
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // because sometimes the very act of loading the dll causes QEMU to crash.
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(),
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  NULL, 0)) {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // For organic brandcodes do not use rlz at all. Empty brandcode usually
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // means a chromium install. This is ok.
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring brand;
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!GoogleUpdateSettings::GetBrand(&brand) || brand.empty() ||
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        GoogleUpdateSettings::IsOrganic(brand))
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Do the initial event recording if is the first run or if we have an
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // empty rlz which means we haven't got a chance to do it.
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring omnibox_rlz;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &omnibox_rlz);
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if ((first_run_ || omnibox_rlz.empty()) && !already_ran_) {
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      already_ran_ = true;
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Record the installation of chrome.
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     rlz_lib::CHROME_OMNIBOX,
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     rlz_lib::INSTALL);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     rlz_lib::CHROME_HOME_PAGE,
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     rlz_lib::INSTALL);
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Record if google is the initial search provider.
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (IsGoogleDefaultSearch()) {
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RLZTracker::RecordProductEvent(rlz_lib::CHROME,
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       rlz_lib::CHROME_OMNIBOX,
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       rlz_lib::SET_TO_GOOGLE);
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Record first user interaction with the omnibox. We call this all the
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // time but the rlz lib should ingore all but the first one.
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (OmniBoxUsageObserver::used()) {
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     rlz_lib::CHROME_OMNIBOX,
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     rlz_lib::FIRST_SEARCH);
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Schedule the daily RLZ ping.
21172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    MessageLoop::current()->PostTask(FROM_HERE, new DailyPingTask());
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool IsGoogleDefaultSearch() {
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!g_browser_process)
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FilePath user_data_dir;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProfileManager* profile_manager = g_browser_process->profile_manager();
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!profile)
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TemplateURL* url_template =
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        profile->GetTemplateURLModel()->GetDefaultSearchProvider();
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url_template)
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TemplateURLRef* urlref = url_template->url();
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!urlref)
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return urlref->HasGoogleBaseURLs();
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Flag that remembers if the delayed task already ran or not.  This is
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // needed only in the first_run case, since we don't want to record the
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // set-to-google event more than once.  We need to worry about this event
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // (and not the others) because it is not a stateful RLZ event.
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static bool already_ran_;
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool first_run_;
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_IMPLICIT_CONSTRUCTORS(DelayedInitTask);
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool DelayedInitTask::already_ran_ = false;
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid OmniBoxUsageObserver::Observe(NotificationType type,
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                   const NotificationSource& source,
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                   const NotificationDetails& details) {
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Needs to be evaluated. See http://crbug.com/62328.
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::ThreadRestrictions::ScopedAllowIO allow_io;
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Try to record event now, else set the flag to try later when we
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // attempt the ping.
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!RLZTracker::RecordProductEvent(rlz_lib::CHROME,
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                      rlz_lib::CHROME_OMNIBOX,
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                      rlz_lib::FIRST_SEARCH))
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    omnibox_used_ = true;
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  else if (send_ping_immediately_) {
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BrowserThread::PostTask(
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        BrowserThread::FILE, FROM_HERE, new DelayedInitTask(first_run_));
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  delete this;
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RLZTracker::InitRlzDelayed(bool first_run, int delay) {
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // A negative delay means that a financial ping should be sent immediately
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // after a first search is recorded, without waiting for the next restart
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // of chrome.  However, we only want this behaviour on first run.
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool send_ping_immediately = false;
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (delay < 0) {
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    send_ping_immediately = true;
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delay = -delay;
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Maximum and minimum delay we would allow to be set through master
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // preferences. Somewhat arbitrary, may need to be adjusted in future.
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int kMaxDelay = 200 * 1000;
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int kMinDelay = 20 * 1000;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delay *= 1000;
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delay = (delay < kMinDelay) ? kMinDelay : delay;
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delay = (delay > kMaxDelay) ? kMaxDelay : delay;
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!OmniBoxUsageObserver::used())
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    new OmniBoxUsageObserver(first_run, send_ping_immediately);
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Schedule the delayed init items.
29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  BrowserThread::PostDelayedTask(
29372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      BrowserThread::FILE, FROM_HERE, new DelayedInitTask(first_run), delay);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RLZTracker::RecordProductEvent(rlz_lib::Product product,
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    rlz_lib::AccessPoint point,
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    rlz_lib::Event event_id) {
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rlz_lib::RecordProductEvent(product, point, event_id);
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RLZTracker::ClearAllProductEvents(rlz_lib::Product product) {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rlz_lib::ClearAllProductEvents(product);
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We implement caching of the answer of get_access_point() if the request
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is for CHROME_OMNIBOX. If we had a successful ping, then we update the
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// cached value.
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point,
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   std::wstring* rlz) {
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static std::wstring cached_ommibox_rlz;
31472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (rlz_lib::CHROME_OMNIBOX == point) {
31572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(rlz_lock);
31672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (access_values_state == ACCESS_VALUES_FRESH) {
31772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      *rlz = cached_ommibox_rlz;
31872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return true;
31972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
32272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Make sure we don't access disk outside of the file context.
32372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // In such case we repost the task on the right thread and return error.
32472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
32572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Caching of access points is now only implemented for the CHROME_OMNIBOX.
32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Thus it is not possible to call this function on another thread for
32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // other access points until proper caching for these has been implemented
32872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // and the code that calls this function can handle synchronous fetching
32972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // of the access point.
33072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DCHECK_EQ(rlz_lib::CHROME_OMNIBOX, point);
33172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
33272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    BrowserThread::PostTask(
33372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        BrowserThread::FILE, FROM_HERE,
33472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        NewRunnableFunction(&RLZTracker::GetAccessPointRlz,
33572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                            point, &cached_ommibox_rlz));
33672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      rlz->erase();
33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char str_rlz[kMaxRlzLength + 1];
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength, NULL))
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *rlz = ASCIIToWide(std::string(str_rlz));
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rlz_lib::CHROME_OMNIBOX == point) {
34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(rlz_lock);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cached_ommibox_rlz.assign(*rlz);
34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    access_values_state = ACCESS_VALUES_FRESH;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid RLZTracker::CleanupRlz() {
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OmniBoxUsageObserver::DeleteInstance();
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
356