OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This code glues the RLZ library DLL with Chrome. It allows Chrome to work | 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 | 6 // with or without the DLL being present. If the DLL is not present the |
7 // functions do nothing and just return false. | 7 // functions do nothing and just return false. |
8 | 8 |
9 #include "chrome/browser/rlz/rlz.h" | 9 #include "chrome/browser/rlz/rlz.h" |
10 | 10 |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include "base/utf_string_conversions.h" | 24 #include "base/utf_string_conversions.h" |
25 #include "chrome/browser/browser_process.h" | 25 #include "chrome/browser/browser_process.h" |
26 #include "chrome/browser/search_engines/template_url.h" | 26 #include "chrome/browser/search_engines/template_url.h" |
27 #include "chrome/browser/search_engines/template_url_service.h" | 27 #include "chrome/browser/search_engines/template_url_service.h" |
28 #include "chrome/browser/search_engines/template_url_service_factory.h" | 28 #include "chrome/browser/search_engines/template_url_service_factory.h" |
29 #include "chrome/common/chrome_notification_types.h" | 29 #include "chrome/common/chrome_notification_types.h" |
30 #include "chrome/common/chrome_paths.h" | 30 #include "chrome/common/chrome_paths.h" |
31 #include "chrome/common/env_vars.h" | 31 #include "chrome/common/env_vars.h" |
32 #include "chrome/installer/util/google_update_settings.h" | 32 #include "chrome/installer/util/google_update_settings.h" |
33 #include "content/browser/browser_thread.h" | 33 #include "content/browser/browser_thread.h" |
34 #include "content/common/notification_registrar.h" | 34 #include "content/browser/tab_contents/navigation_entry.h" |
35 #include "content/common/notification_service.h" | 35 #include "content/common/notification_service.h" |
36 | 36 |
37 namespace { | 37 namespace { |
38 | 38 |
39 enum { | 39 // Organic brands all start with GG, such as GGCM. |
40 ACCESS_VALUES_STALE, // Possibly new values available. | 40 static bool is_organic(const std::wstring& brand) { |
41 ACCESS_VALUES_FRESH // The cached values are current. | 41 return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG"); |
42 }; | 42 } |
43 | 43 |
44 // Tracks if we have tried and succeeded sending the ping. This helps us | 44 void RecordProductEvents(bool first_run, bool google_default_search, |
45 // decide if we need to refresh the cached RLZ string. | 45 bool google_default_homepage, bool already_ran, |
46 volatile int access_values_state = ACCESS_VALUES_STALE; | 46 bool omnibox_used, bool homepage_used) { |
47 base::Lock rlz_lock; | 47 // Record the installation of chrome. We call this all the time but the rlz |
| 48 // lib should ingore all but the first one. |
| 49 rlz_lib::RecordProductEvent(rlz_lib::CHROME, |
| 50 rlz_lib::CHROME_OMNIBOX, |
| 51 rlz_lib::INSTALL); |
| 52 rlz_lib::RecordProductEvent(rlz_lib::CHROME, |
| 53 rlz_lib::CHROME_HOME_PAGE, |
| 54 rlz_lib::INSTALL); |
48 | 55 |
49 bool SendFinancialPing(const std::wstring& brand, const std::wstring& lang, | 56 if (!already_ran) { |
50 const std::wstring& referral, bool exclude_id) { | 57 // Do the initial event recording if is the first run or if we have an |
| 58 // empty rlz which means we haven't got a chance to do it. |
| 59 char omnibox_rlz[rlz_lib::kMaxRlzLength + 1]; |
| 60 if (!rlz_lib::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, omnibox_rlz, |
| 61 rlz_lib::kMaxRlzLength, NULL)) { |
| 62 omnibox_rlz[0] = 0; |
| 63 } |
| 64 |
| 65 // Record if google is the initial search provider and/or home page. |
| 66 if ((first_run || omnibox_rlz[0] == 0) && google_default_search) { |
| 67 rlz_lib::RecordProductEvent(rlz_lib::CHROME, |
| 68 rlz_lib::CHROME_OMNIBOX, |
| 69 rlz_lib::SET_TO_GOOGLE); |
| 70 } |
| 71 |
| 72 char homepage_rlz[rlz_lib::kMaxRlzLength + 1]; |
| 73 if (!rlz_lib::GetAccessPointRlz(rlz_lib::CHROME_HOME_PAGE, homepage_rlz, |
| 74 rlz_lib::kMaxRlzLength, NULL)) { |
| 75 homepage_rlz[0] = 0; |
| 76 } |
| 77 |
| 78 if ((first_run || homepage_rlz[0] == 0) && google_default_homepage) { |
| 79 rlz_lib::RecordProductEvent(rlz_lib::CHROME, |
| 80 rlz_lib::CHROME_HOME_PAGE, |
| 81 rlz_lib::SET_TO_GOOGLE); |
| 82 } |
| 83 } |
| 84 |
| 85 // Record first user interaction with the omnibox. We call this all the |
| 86 // time but the rlz lib should ingore all but the first one. |
| 87 if (omnibox_used) { |
| 88 rlz_lib::RecordProductEvent(rlz_lib::CHROME, |
| 89 rlz_lib::CHROME_OMNIBOX, |
| 90 rlz_lib::FIRST_SEARCH); |
| 91 } |
| 92 |
| 93 // Record first user interaction with the home page. We call this all the |
| 94 // time but the rlz lib should ingore all but the first one. |
| 95 if (homepage_used) { |
| 96 rlz_lib::RecordProductEvent(rlz_lib::CHROME, |
| 97 rlz_lib::CHROME_HOME_PAGE, |
| 98 rlz_lib::FIRST_SEARCH); |
| 99 } |
| 100 } |
| 101 |
| 102 bool SendFinancialPing(const std::wstring& brand, |
| 103 const std::wstring& lang, |
| 104 const std::wstring& referral, |
| 105 bool exclude_id) { |
51 rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, | 106 rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, |
52 rlz_lib::CHROME_HOME_PAGE, | 107 rlz_lib::CHROME_HOME_PAGE, |
53 rlz_lib::NO_ACCESS_POINT}; | 108 rlz_lib::NO_ACCESS_POINT}; |
54 std::string brand_ascii(WideToASCII(brand)); | 109 std::string brand_ascii(WideToASCII(brand)); |
55 std::string lang_ascii(WideToASCII(lang)); | 110 std::string lang_ascii(WideToASCII(lang)); |
56 std::string referral_ascii(WideToASCII(referral)); | 111 std::string referral_ascii(WideToASCII(referral)); |
57 | 112 |
58 // If chrome has been reactivated, send a ping for this brand as well. | 113 // If chrome has been reactivated, send a ping for this brand as well. |
59 // We ignore the return value of SendFinancialPing() since we'll try again | 114 // We ignore the return value of SendFinancialPing() since we'll try again |
60 // later anyway. Callers of this function are only interested in whether | 115 // later anyway. Callers of this function are only interested in whether |
61 // the ping for the main brand succeeded or not. | 116 // the ping for the main brand succeeded or not. |
62 std::wstring reactivation_brand; | 117 std::wstring reactivation_brand; |
63 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { | 118 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { |
64 std::string reactivation_brand_ascii(WideToASCII(reactivation_brand)); | 119 std::string reactivation_brand_ascii(WideToASCII(reactivation_brand)); |
65 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | 120 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
66 rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", | 121 rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", |
67 reactivation_brand_ascii.c_str(), | 122 reactivation_brand_ascii.c_str(), |
68 referral_ascii.c_str(), lang_ascii.c_str(), | 123 referral_ascii.c_str(), lang_ascii.c_str(), |
69 exclude_id, NULL, true); | 124 exclude_id, NULL, true); |
70 } | 125 } |
71 | 126 |
72 return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", | 127 return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", |
73 brand_ascii.c_str(), referral_ascii.c_str(), | 128 brand_ascii.c_str(), referral_ascii.c_str(), |
74 lang_ascii.c_str(), exclude_id, NULL, true); | 129 lang_ascii.c_str(), exclude_id, NULL, true); |
75 } | 130 } |
76 | 131 |
77 // This class leverages the AutocompleteEditModel notification to know when | |
78 // the user first interacted with the omnibox and set a global accordingly. | |
79 class OmniBoxUsageObserver : public NotificationObserver { | |
80 public: | |
81 OmniBoxUsageObserver(bool first_run, bool send_ping_immediately, | |
82 bool google_default_search) | |
83 : first_run_(first_run), | |
84 send_ping_immediately_(send_ping_immediately), | |
85 google_default_search_(google_default_search) { | |
86 registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, | |
87 NotificationService::AllSources()); | |
88 // If instant is enabled we'll start searching as soon as the user starts | |
89 // typing in the omnibox (which triggers INSTANT_CONTROLLER_UPDATED). | |
90 registrar_.Add(this, chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, | |
91 NotificationService::AllSources()); | |
92 omnibox_used_ = false; | |
93 DCHECK(!instance_); | |
94 instance_ = this; | |
95 } | |
96 | |
97 virtual void Observe(int type, | |
98 const NotificationSource& source, | |
99 const NotificationDetails& details); | |
100 | |
101 static bool used() { | |
102 return omnibox_used_; | |
103 } | |
104 | |
105 // Deletes the single instance of OmniBoxUsageObserver. | |
106 static void DeleteInstance() { | |
107 delete instance_; | |
108 } | |
109 | |
110 private: | |
111 // Dtor is private so the object cannot be created on the stack. | |
112 ~OmniBoxUsageObserver() { | |
113 instance_ = NULL; | |
114 } | |
115 | |
116 static bool omnibox_used_; | |
117 | |
118 // There should only be one instance created at a time, and instance_ points | |
119 // to that instance. | |
120 // NOTE: this is only non-null for the amount of time it is needed. Once the | |
121 // instance_ is no longer needed (or Chrome is exiting), this is null. | |
122 static OmniBoxUsageObserver* instance_; | |
123 | |
124 NotificationRegistrar registrar_; | |
125 bool first_run_; | |
126 bool send_ping_immediately_; | |
127 bool google_default_search_; | |
128 }; | |
129 | |
130 bool OmniBoxUsageObserver::omnibox_used_ = false; | |
131 OmniBoxUsageObserver* OmniBoxUsageObserver::instance_ = NULL; | |
132 | |
133 // This task is run in the file thread, so to not block it for a long time | |
134 // we use a throwaway thread to do the blocking url request. | |
135 class DailyPingTask : public Task { | |
136 public: | |
137 virtual ~DailyPingTask() { | |
138 } | |
139 virtual void Run() { | |
140 // We use a transient thread because we have no guarantees about | |
141 // how long the RLZ lib can block us. | |
142 _beginthread(PingNow, 0, NULL); | |
143 } | |
144 | |
145 private: | |
146 // Causes a ping to the server using WinInet. | |
147 static void _cdecl PingNow(void*) { | |
148 // Needs to be evaluated. See http://crbug.com/62328. | |
149 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
150 | |
151 std::wstring lang; | |
152 GoogleUpdateSettings::GetLanguage(&lang); | |
153 if (lang.empty()) | |
154 lang = L"en"; | |
155 std::wstring brand; | |
156 GoogleUpdateSettings::GetBrand(&brand); | |
157 std::wstring referral; | |
158 GoogleUpdateSettings::GetReferral(&referral); | |
159 if (SendFinancialPing(brand, lang, referral, is_organic(brand))) { | |
160 base::AutoLock lock(rlz_lock); | |
161 access_values_state = ACCESS_VALUES_STALE; | |
162 GoogleUpdateSettings::ClearReferral(); | |
163 } | |
164 } | |
165 | |
166 // Organic brands all start with GG, such as GGCM. | |
167 static bool is_organic(const std::wstring& brand) { | |
168 return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG"); | |
169 } | |
170 }; | |
171 | |
172 // Performs late RLZ initialization and RLZ event recording for chrome. | |
173 // This task needs to run on the UI thread. | |
174 class DelayedInitTask : public Task { | |
175 public: | |
176 DelayedInitTask(bool first_run, bool google_default_search) | |
177 : first_run_(first_run), | |
178 google_default_search_(google_default_search) { | |
179 } | |
180 virtual ~DelayedInitTask() { | |
181 } | |
182 virtual void Run() { | |
183 // For non-interactive tests we don't do the rest of the initialization | |
184 // because sometimes the very act of loading the dll causes QEMU to crash. | |
185 if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(), | |
186 NULL, 0)) { | |
187 return; | |
188 } | |
189 // For organic brandcodes do not use rlz at all. Empty brandcode usually | |
190 // means a chromium install. This is ok. | |
191 std::wstring brand; | |
192 if (!GoogleUpdateSettings::GetBrand(&brand) || brand.empty() || | |
193 GoogleUpdateSettings::IsOrganic(brand)) | |
194 return; | |
195 | |
196 RecordProductEvents(first_run_, google_default_search_, already_ran_); | |
197 | |
198 // If chrome has been reactivated, record the events for this brand | |
199 // as well. | |
200 std::wstring reactivation_brand; | |
201 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { | |
202 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | |
203 RecordProductEvents(first_run_, google_default_search_, already_ran_); | |
204 } | |
205 | |
206 already_ran_ = true; | |
207 | |
208 // Schedule the daily RLZ ping. | |
209 MessageLoop::current()->PostTask(FROM_HERE, new DailyPingTask()); | |
210 } | |
211 | |
212 private: | |
213 static void RecordProductEvents(bool first_run, bool google_default_search, | |
214 bool already_ran) { | |
215 // Record the installation of chrome. We call this all the time but the rlz | |
216 // lib should ingore all but the first one. | |
217 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
218 rlz_lib::CHROME_OMNIBOX, | |
219 rlz_lib::INSTALL); | |
220 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
221 rlz_lib::CHROME_HOME_PAGE, | |
222 rlz_lib::INSTALL); | |
223 | |
224 // Do the initial event recording if is the first run or if we have an | |
225 // empty rlz which means we haven't got a chance to do it. | |
226 char omnibox_rlz[rlz_lib::kMaxRlzLength + 1]; | |
227 if (!rlz_lib::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, omnibox_rlz, | |
228 rlz_lib::kMaxRlzLength, NULL)) { | |
229 omnibox_rlz[0] = 0; | |
230 } | |
231 | |
232 // Record if google is the initial search provider. | |
233 if ((first_run || omnibox_rlz[0] == 0) && google_default_search && | |
234 !already_ran) { | |
235 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
236 rlz_lib::CHROME_OMNIBOX, | |
237 rlz_lib::SET_TO_GOOGLE); | |
238 } | |
239 | |
240 // Record first user interaction with the omnibox. We call this all the | |
241 // time but the rlz lib should ingore all but the first one. | |
242 if (OmniBoxUsageObserver::used()) { | |
243 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
244 rlz_lib::CHROME_OMNIBOX, | |
245 rlz_lib::FIRST_SEARCH); | |
246 } | |
247 } | |
248 | |
249 // Flag that remembers if the delayed task already ran or not. This is | |
250 // needed only in the first_run case, since we don't want to record the | |
251 // set-to-google event more than once. We need to worry about this event | |
252 // (and not the others) because it is not a stateful RLZ event. | |
253 static bool already_ran_; | |
254 | |
255 bool first_run_; | |
256 | |
257 // True if Google is the default search engine for the first profile starting | |
258 // in a browser during first run. | |
259 bool google_default_search_; | |
260 | |
261 }; | |
262 | |
263 bool DelayedInitTask::already_ran_ = false; | |
264 | |
265 void OmniBoxUsageObserver::Observe(int type, | |
266 const NotificationSource& source, | |
267 const NotificationDetails& details) { | |
268 // Needs to be evaluated. See http://crbug.com/62328. | |
269 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
270 | |
271 // Try to record event now, else set the flag to try later when we | |
272 // attempt the ping. | |
273 if (!RLZTracker::RecordProductEvent(rlz_lib::CHROME, | |
274 rlz_lib::CHROME_OMNIBOX, | |
275 rlz_lib::FIRST_SEARCH)) | |
276 omnibox_used_ = true; | |
277 else if (send_ping_immediately_) { | |
278 BrowserThread::PostTask( | |
279 BrowserThread::FILE, FROM_HERE, new DelayedInitTask(first_run_, | |
280 google_default_search_)); | |
281 } | |
282 | |
283 delete this; | |
284 } | |
285 | |
286 } // namespace | 132 } // namespace |
287 | 133 |
| 134 RLZTracker* RLZTracker::tracker_ = NULL; |
| 135 |
| 136 // static |
| 137 RLZTracker* RLZTracker::GetInstance() { |
| 138 return tracker_ ? tracker_ : Singleton<RLZTracker>::get(); |
| 139 } |
| 140 |
| 141 RLZTracker::RLZTracker() |
| 142 : first_run_(false), |
| 143 send_ping_immediately_(false), |
| 144 google_default_search_(false), |
| 145 already_ran_(false), |
| 146 omnibox_used_(false), |
| 147 homepage_used_(false) { |
| 148 } |
| 149 |
| 150 RLZTracker::~RLZTracker() { |
| 151 } |
| 152 |
288 bool RLZTracker::InitRlzDelayed(bool first_run, int delay, | 153 bool RLZTracker::InitRlzDelayed(bool first_run, int delay, |
289 bool google_default_search) { | 154 bool google_default_search, |
| 155 bool google_default_homepage) { |
| 156 return GetInstance()->Init(first_run, delay, google_default_search, |
| 157 google_default_homepage); |
| 158 } |
| 159 |
| 160 bool RLZTracker::Init(bool first_run, int delay, bool google_default_search, |
| 161 bool google_default_homepage) { |
| 162 first_run_ = first_run; |
| 163 google_default_search_ = google_default_search; |
| 164 google_default_homepage_ = google_default_homepage; |
| 165 |
290 // A negative delay means that a financial ping should be sent immediately | 166 // A negative delay means that a financial ping should be sent immediately |
291 // after a first search is recorded, without waiting for the next restart | 167 // after a first search is recorded, without waiting for the next restart |
292 // of chrome. However, we only want this behaviour on first run. | 168 // of chrome. However, we only want this behaviour on first run. |
293 bool send_ping_immediately = false; | 169 send_ping_immediately_ = false; |
294 if (delay < 0) { | 170 if (delay < 0) { |
295 send_ping_immediately = true; | 171 send_ping_immediately_ = true; |
296 delay = -delay; | 172 delay = -delay; |
297 } | 173 } |
298 | 174 |
299 // Maximum and minimum delay we would allow to be set through master | 175 // Maximum and minimum delay we would allow to be set through master |
300 // preferences. Somewhat arbitrary, may need to be adjusted in future. | 176 // preferences. Somewhat arbitrary, may need to be adjusted in future. |
301 const int kMaxDelay = 200 * 1000; | 177 const int kMaxDelay = 200 * 1000; |
302 const int kMinDelay = 20 * 1000; | 178 const int kMinDelay = 20 * 1000; |
303 | 179 |
304 delay *= 1000; | 180 delay *= 1000; |
305 delay = (delay < kMinDelay) ? kMinDelay : delay; | 181 delay = (delay < kMinDelay) ? kMinDelay : delay; |
306 delay = (delay > kMaxDelay) ? kMaxDelay : delay; | 182 delay = (delay > kMaxDelay) ? kMaxDelay : delay; |
307 | 183 |
308 if (!OmniBoxUsageObserver::used()) | 184 // Register for notifications from the omnibox so that we can record when |
309 new OmniBoxUsageObserver(first_run, send_ping_immediately, | 185 // the user performs a first search. |
310 google_default_search); | 186 registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, |
| 187 NotificationService::AllSources()); |
| 188 // If instant is enabled we'll start searching as soon as the user starts |
| 189 // typing in the omnibox (which triggers INSTANT_CONTROLLER_UPDATED). |
| 190 registrar_.Add(this, chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, |
| 191 NotificationService::AllSources()); |
311 | 192 |
312 // Schedule the delayed init items. | 193 // Register for notifications from navigations, to see if the user has used |
| 194 // the home page. |
| 195 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
| 196 NotificationService::AllSources()); |
| 197 |
| 198 ScheduleDelayedInit(delay); |
| 199 return true; |
| 200 } |
| 201 |
| 202 void RLZTracker::ScheduleDelayedInit(int delay) { |
313 BrowserThread::PostDelayedTask( | 203 BrowserThread::PostDelayedTask( |
314 BrowserThread::FILE, | 204 BrowserThread::FILE, |
315 FROM_HERE, | 205 FROM_HERE, |
316 new DelayedInitTask(first_run, google_default_search), | 206 NewRunnableMethod(this, &RLZTracker::DelayedInit), |
317 delay); | 207 delay); |
318 return true; | 208 } |
| 209 |
| 210 void RLZTracker::DelayedInit() { |
| 211 // For organic brandcodes do not use rlz at all. Empty brandcode usually |
| 212 // means a chromium install. This is ok. |
| 213 std::wstring brand; |
| 214 if (!GoogleUpdateSettings::GetBrand(&brand) || brand.empty() || |
| 215 GoogleUpdateSettings::IsOrganic(brand)) |
| 216 return; |
| 217 |
| 218 RecordProductEvents(first_run_, google_default_search_, |
| 219 google_default_homepage_, already_ran_, |
| 220 omnibox_used_, homepage_used_); |
| 221 |
| 222 // If chrome has been reactivated, record the events for this brand |
| 223 // as well. |
| 224 std::wstring reactivation_brand; |
| 225 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { |
| 226 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
| 227 RecordProductEvents(first_run_, google_default_search_, |
| 228 google_default_homepage_, already_ran_, |
| 229 omnibox_used_, homepage_used_); |
| 230 } |
| 231 |
| 232 already_ran_ = true; |
| 233 |
| 234 ScheduleFinancialPing(); |
| 235 } |
| 236 |
| 237 void RLZTracker::ScheduleFinancialPing() { |
| 238 _beginthread(PingNow, 0, this); |
| 239 } |
| 240 |
| 241 // static |
| 242 void _cdecl RLZTracker::PingNow(void* arg) { |
| 243 RLZTracker* tracker = reinterpret_cast<RLZTracker*>(arg); |
| 244 tracker->PingNowImpl(); |
| 245 } |
| 246 |
| 247 void RLZTracker::PingNowImpl() { |
| 248 // Needs to be evaluated. See http://crbug.com/62328. |
| 249 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 250 |
| 251 std::wstring lang; |
| 252 GoogleUpdateSettings::GetLanguage(&lang); |
| 253 if (lang.empty()) |
| 254 lang = L"en"; |
| 255 std::wstring brand; |
| 256 GoogleUpdateSettings::GetBrand(&brand); |
| 257 std::wstring referral; |
| 258 GoogleUpdateSettings::GetReferral(&referral); |
| 259 if (SendFinancialPing(brand, lang, referral, is_organic(brand))) { |
| 260 GoogleUpdateSettings::ClearReferral(); |
| 261 base::AutoLock lock(cache_lock_); |
| 262 rlz_cache_.clear(); |
| 263 } |
| 264 } |
| 265 |
| 266 bool RLZTracker::SendFinancialPing(const std::wstring& brand, |
| 267 const std::wstring& lang, |
| 268 const std::wstring& referral, |
| 269 bool exclude_id) { |
| 270 return ::SendFinancialPing(brand, lang, referral, exclude_id); |
| 271 } |
| 272 |
| 273 void RLZTracker::Observe(int type, |
| 274 const NotificationSource& source, |
| 275 const NotificationDetails& details) { |
| 276 // Needs to be evaluated. See http://crbug.com/62328. |
| 277 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 278 |
| 279 rlz_lib::AccessPoint point; |
| 280 bool* record_used = NULL; |
| 281 bool call_record = false; |
| 282 |
| 283 switch (type) { |
| 284 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: |
| 285 case chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED: |
| 286 point = rlz_lib::CHROME_OMNIBOX; |
| 287 record_used = &omnibox_used_; |
| 288 call_record = true; |
| 289 |
| 290 registrar_.Remove(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, |
| 291 NotificationService::AllSources()); |
| 292 registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, |
| 293 NotificationService::AllSources()); |
| 294 break; |
| 295 case content::NOTIFICATION_NAV_ENTRY_PENDING: { |
| 296 const NavigationEntry* entry = Details<NavigationEntry>(details).ptr(); |
| 297 if (entry != NULL && |
| 298 ((entry->transition_type() & RLZ_PAGETRANSITION_HOME_PAGE) != 0)) { |
| 299 point = rlz_lib::CHROME_HOME_PAGE; |
| 300 record_used = &homepage_used_; |
| 301 call_record = true; |
| 302 |
| 303 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
| 304 NotificationService::AllSources()); |
| 305 } |
| 306 break; |
| 307 } |
| 308 default: |
| 309 NOTREACHED(); |
| 310 break; |
| 311 } |
| 312 |
| 313 if (call_record) { |
| 314 // Try to record event now, else set the flag to try later when we |
| 315 // attempt the ping. |
| 316 if (!RecordProductEvent(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH)) |
| 317 *record_used = true; |
| 318 else if (send_ping_immediately_ && point == rlz_lib::CHROME_OMNIBOX) { |
| 319 ScheduleDelayedInit(0); |
| 320 } |
| 321 } |
319 } | 322 } |
320 | 323 |
321 bool RLZTracker::RecordProductEvent(rlz_lib::Product product, | 324 bool RLZTracker::RecordProductEvent(rlz_lib::Product product, |
322 rlz_lib::AccessPoint point, | 325 rlz_lib::AccessPoint point, |
323 rlz_lib::Event event_id) { | 326 rlz_lib::Event event_id) { |
324 bool ret = rlz_lib::RecordProductEvent(product, point, event_id); | 327 bool ret = rlz_lib::RecordProductEvent(product, point, event_id); |
325 | 328 |
326 // If chrome has been reactivated, record the event for this brand as well. | 329 // If chrome has been reactivated, record the event for this brand as well. |
327 std::wstring reactivation_brand; | 330 std::wstring reactivation_brand; |
328 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { | 331 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { |
329 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | 332 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
330 ret &= rlz_lib::RecordProductEvent(product, point, event_id); | 333 ret &= rlz_lib::RecordProductEvent(product, point, event_id); |
331 } | 334 } |
332 | 335 |
333 return ret; | 336 return ret; |
334 } | 337 } |
335 | 338 |
336 // We implement caching of the answer of get_access_point() if the request | 339 // GetAccessPointRlz() caches RLZ strings for all access points. If we had |
337 // is for CHROME_OMNIBOX. If we had a successful ping, then we update the | 340 // a successful ping, then we update the cached value. |
338 // cached value. | |
339 | |
340 bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point, | 341 bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point, |
341 std::wstring* rlz) { | 342 std::wstring* rlz) { |
342 static std::wstring cached_ommibox_rlz; | 343 return GetInstance()->GetAccessPointRlzImpl(point, rlz); |
343 if (rlz_lib::CHROME_OMNIBOX == point) { | 344 } |
344 base::AutoLock lock(rlz_lock); | 345 |
345 if (access_values_state == ACCESS_VALUES_FRESH) { | 346 // GetAccessPointRlz() caches RLZ strings for all access points. If we had |
346 *rlz = cached_ommibox_rlz; | 347 // a successful ping, then we update the cached value. |
| 348 bool RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point, |
| 349 std::wstring* rlz) { |
| 350 // If the RLZ string for the specified access point is already cached, |
| 351 // simply return its value. |
| 352 { |
| 353 base::AutoLock lock(cache_lock_); |
| 354 if (rlz_cache_.find(point) != rlz_cache_.end()) { |
| 355 if (rlz) |
| 356 *rlz = rlz_cache_[point]; |
347 return true; | 357 return true; |
348 } | 358 } |
349 } | 359 } |
350 | 360 |
351 // Make sure we don't access disk outside of the file context. | 361 // Make sure we don't access disk outside of the I/O thread. |
352 // In such case we repost the task on the right thread and return error. | 362 // In such case we repost the task on the right thread and return error. |
353 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { | 363 if (ScheduleGetAccessPointRlz(point)) |
354 // Caching of access points is now only implemented for the CHROME_OMNIBOX. | 364 return false; |
355 // Thus it is not possible to call this function on another thread for | |
356 // other access points until proper caching for these has been implemented | |
357 // and the code that calls this function can handle synchronous fetching | |
358 // of the access point. | |
359 DCHECK_EQ(rlz_lib::CHROME_OMNIBOX, point); | |
360 | |
361 BrowserThread::PostTask( | |
362 BrowserThread::FILE, FROM_HERE, | |
363 NewRunnableFunction(&RLZTracker::GetAccessPointRlz, | |
364 point, &cached_ommibox_rlz)); | |
365 rlz->erase(); | |
366 return false; | |
367 } | |
368 | 365 |
369 char str_rlz[rlz_lib::kMaxRlzLength + 1]; | 366 char str_rlz[rlz_lib::kMaxRlzLength + 1]; |
370 if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength, NULL)) | 367 if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength, NULL)) |
371 return false; | 368 return false; |
372 *rlz = ASCIIToWide(std::string(str_rlz)); | 369 |
373 if (rlz_lib::CHROME_OMNIBOX == point) { | 370 std::wstring rlz_local(ASCIIToWide(std::string(str_rlz))); |
374 base::AutoLock lock(rlz_lock); | 371 if (rlz) |
375 cached_ommibox_rlz.assign(*rlz); | 372 *rlz = rlz_local; |
376 access_values_state = ACCESS_VALUES_FRESH; | 373 |
377 } | 374 base::AutoLock lock(cache_lock_); |
| 375 rlz_cache_[point] = rlz_local; |
| 376 return true; |
| 377 } |
| 378 |
| 379 bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) { |
| 380 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) |
| 381 return false; |
| 382 |
| 383 std::wstring* not_used = NULL; |
| 384 BrowserThread::PostTask( |
| 385 BrowserThread::FILE, FROM_HERE, |
| 386 NewRunnableFunction(&RLZTracker::GetAccessPointRlz, point, not_used)); |
378 return true; | 387 return true; |
379 } | 388 } |
380 | 389 |
381 // static | 390 // static |
382 void RLZTracker::CleanupRlz() { | 391 void RLZTracker::CleanupRlz() { |
383 OmniBoxUsageObserver::DeleteInstance(); | 392 GetInstance()->rlz_cache_.clear(); |
| 393 GetInstance()->registrar_.RemoveAll(); |
384 } | 394 } |
OLD | NEW |